CB-153 Batch update implementation

This commit is contained in:
Serge Rider
2020-06-25 19:38:28 +03:00
parent f2fd6ac4c8
commit dcf9daa4ba
5 changed files with 172 additions and 4 deletions
@@ -68,8 +68,9 @@ public interface DBWServiceSQL extends DBWService {
WebSQLExecuteInfo updateResultsDataBatch(
@NotNull WebSQLContextInfo contextInfo,
@NotNull String resultsId,
@NotNull List<Object> updateRow,
@NotNull Map<String, Object> updateValues) throws DBWebException;
@Nullable List<WebSQLResultsRow> updatedRows,
@Nullable List<WebSQLResultsRow> deletedRows,
@Nullable List<WebSQLResultsRow> addedRows) throws DBWebException;
@WebAction
WebAsyncTaskInfo asyncExecuteQuery(@NotNull WebSQLContextInfo contextInfo, @NotNull String sql, @Nullable WebSQLDataFilter filter) throws DBException;
@@ -294,6 +294,106 @@ public class WebSQLProcessor {
return result;
}
@WebAction
public WebSQLExecuteInfo updateResultsDataBatch(
@NotNull WebSQLContextInfo contextInfo,
@NotNull String resultsId,
@Nullable List<WebSQLResultsRow> updatedRows,
@Nullable List<WebSQLResultsRow> deletedRows,
@Nullable List<WebSQLResultsRow> addedRows) throws DBWebException
{
WebSQLResultsInfo resultsInfo = contextInfo.getResults(resultsId);
DBDRowIdentifier rowIdentifier = resultsInfo.getDefaultRowIdentifier();
if (rowIdentifier == null) {
throw new DBWebException("Can't detect row identifier for results '" + resultsId + "'");
}
DBSEntity dataContainer = rowIdentifier.getEntity();
if (!(dataContainer instanceof DBSDataManipulator)) {
throw new DBWebException("Data container '" + dataContainer.getName() + "' is not editable");
}
DBSDataManipulator dataManipulator = (DBSDataManipulator) dataContainer;
DBRProgressMonitor monitor = webSession.getProgressMonitor();
WebSQLExecuteInfo result = new WebSQLExecuteInfo();
List<WebSQLQueryResults> queryResults = new ArrayList<>();
try {
DBExecUtils.tryExecuteRecover(monitor, connection.getDataSource(), param -> {
try {
DBCExecutionContext executionContext = getExecutionContext(dataManipulator);
try (DBCSession session = executionContext.openSession(monitor, DBCExecutionPurpose.USER, "Update rows in container")) {
WebExecutionSource executionSource = new WebExecutionSource(dataManipulator, executionContext, this);
DBDAttributeBinding[] allAttributes = resultsInfo.getAttributes();
DBDAttributeBinding[] keyAttributes = rowIdentifier.getAttributes().toArray(new DBDAttributeBinding[0]);
if (!CommonUtils.isEmpty(updatedRows)) {
for (WebSQLResultsRow row : updatedRows) {
Map<String, Object> updateValues = row.getUpdateValues();
if (CommonUtils.isEmpty(row.getData()) || CommonUtils.isEmpty(updateValues)) {
continue;
}
DBDAttributeBinding[] updateAttributes = new DBDAttributeBinding[updateValues.size()];
// Final row is what we return back
Object[] finalRow = row.getData().toArray();
int index = 0;
for (String indexStr : updateValues.keySet()) {
int attrIndex = CommonUtils.toInt(indexStr, -1);
updateAttributes[index++] = allAttributes[attrIndex];
}
Object[] rowValues = new Object[updateAttributes.length + keyAttributes.length];
for (int i = 0; i < updateAttributes.length; i++) {
DBDAttributeBinding updateAttribute = updateAttributes[i];
Object cellRawValue = updateValues.get(String.valueOf(updateAttribute.getOrdinalPosition()));
Object realCellValue = updateAttribute.getValueHandler().getValueFromObject(session, updateAttribute, cellRawValue, false, true);
rowValues[i] = realCellValue;
finalRow[updateAttribute.getOrdinalPosition()] = WebSQLUtils.makeWebCellValue(monitor, null, realCellValue);
}
for (int i = 0; i < keyAttributes.length; i++) {
DBDAttributeBinding keyAttribute = keyAttributes[i];
Object cellValueRaw = finalRow[keyAttribute.getOrdinalPosition()];
rowValues[updateAttributes.length + i] = keyAttribute.getValueHandler().getValueFromObject(session, keyAttribute, cellValueRaw, false, true);
}
DBSDataManipulator.ExecuteBatch updateBatch = dataManipulator.updateData(session, updateAttributes, keyAttributes, null, executionSource);
updateBatch.add(rowValues);
DBCStatistics statistics = updateBatch.execute(session);
WebSQLQueryResultSet updatedResultSet = new WebSQLQueryResultSet();
updatedResultSet.setResultsInfo(resultsInfo);
updatedResultSet.setColumns(resultsInfo.getAttributes());
updatedResultSet.setRows(new Object[][]{finalRow});
WebSQLQueryResults updateResults = new WebSQLQueryResults();
updateResults.setUpdateRowCount((int) statistics.getRowsUpdated());
updateResults.setResultSet(updatedResultSet);
queryResults.add(updateResults);
result.setDuration(result.getDuration() + statistics.getExecuteTime());
}
}
if (!CommonUtils.isEmpty(updatedRows)) {
throw new DBCException("New row add is not supported");
}
if (!CommonUtils.isEmpty(deletedRows)) {
throw new DBCException("Row delete is not supported");
}
}
} catch (Exception e) {
throw new InvocationTargetException(e);
}
});
} catch (DBException e) {
throw new DBWebException("Error updating data", e);
}
result.setResults(queryResults.toArray(new WebSQLQueryResults[0]));
return result;
}
@NotNull
public <T> T getDataContainerByNodePath(DBRProgressMonitor monitor, @NotNull String containerPath, Class<T> type) throws DBException {
DBNNode node = webSession.getNavigatorModel().getNodeByPath(monitor, containerPath);
@@ -0,0 +1,47 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2020 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service.sql;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import java.util.List;
import java.util.Map;
/**
* Web query results row.
*/
public class WebSQLResultsRow {
private List<?> data;
private Map<String, Object> updateValues;
public WebSQLResultsRow() {
}
public WebSQLResultsRow(Map<String, Object> map) {
data = JSONUtils.getObjectList(map, "data");
updateValues = JSONUtils.getObject(map, "updateValues");
}
public List<?> getData() {
return data;
}
public Map<String, Object> getUpdateValues() {
return updateValues;
}
}
@@ -24,9 +24,12 @@ import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.service.sql.impl.WebServiceSQL;
import org.jkiss.dbeaver.DBException;
import org.jkiss.utils.CommonUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Web service implementation
@@ -90,6 +93,14 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL> {
env.getArgument("updateRow"),
env.getArgument("updateValues")
))
.dataFetcher("updateResultsDataBatch", env ->
getService(env).updateResultsDataBatch(
getSQLContext(env),
env.getArgument("resultsId"),
getResultsRow(env, "updatedRows"),
getResultsRow(env, "deletedRows"),
getResultsRow(env, "addedRows")
))
.dataFetcher("asyncSqlExecuteQuery", env ->
getService(env).asyncExecuteQuery(
getSQLContext(env),
@@ -154,4 +165,13 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL> {
Map<String, Object> filterProps = env.getArgument("filter");
return filterProps == null ? null : new WebSQLDataFilter(filterProps);
}
private static List<WebSQLResultsRow> getResultsRow(DataFetchingEnvironment env, String param) {
List<Map<String, Object>> mapList = env.getArgument("param");
if (CommonUtils.isEmpty(mapList)) {
return null;
}
return mapList.stream().map(WebSQLResultsRow::new).collect(Collectors.toList());
}
}
@@ -144,8 +144,8 @@ public class WebServiceSQL implements DBWServiceSQL {
}
@Override
public WebSQLExecuteInfo updateResultsDataBatch(@NotNull WebSQLContextInfo contextInfo, @NotNull String resultsId, @NotNull List<Object> updateRow, @NotNull Map<String, Object> updateValues) throws DBWebException {
throw new DBWebException("Not supported");
public WebSQLExecuteInfo updateResultsDataBatch(@NotNull WebSQLContextInfo contextInfo, @NotNull String resultsId, @Nullable List<WebSQLResultsRow> updatedRows, @Nullable List<WebSQLResultsRow> deletedRows, @Nullable List<WebSQLResultsRow> addedRows) throws DBWebException {
return contextInfo.getProcessor().updateResultsDataBatch(contextInfo, resultsId, updatedRows, deletedRows, addedRows);
}
@NotNull