mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
Cb 4457 subcollections firestore (#2338)
* CB-4457. Add api for read subcollections firestore * CB-4457. Move firestore to ee module * CB-4457. Move firestore to ee module * CB-4457. Added annotations for firestore * CB-4457. Added metaData * CB-4457. Fixed build * CB-4457 add hasChildrenCollection flag * CB-4457. Add new resultsRow * CB-4457. Renamed SQLResultRowMetaData parameters * CB-4457 add rows with metadata to schema * CB-4457. Fix gql * CB-4457. Added logic to get Firestore subcollection * CB-4457. Refactor result, rename gql, added new type to return gql * CB-4457. Revert list to map * CB-4457. Get Subcollections info * CB-4457. Refactor code * Added sceleton for insert subcollection * CB-4457. Added isSupportsDataFilter flag for subcollection * CB-4457 add locales * CB-4457. Added isSupportsDataFilter flag for subcollection * CB-4457. Added update/insert logic for subcollection * CB-4457 support collection editing * CB-4457. Refactor after review, moved hierarchical model to ee. * CB-4457 add SerializableKey * CB-4457 keep only new rowsWithMetaData api * CB-4457 review fixes * CB-4457 review fixes * CB-4457. Refactor after review. Added logic for delete * CB-4457 pass metadata in deleted rows * CB-4457 check row for undefined * CB-4457 pass metadata when editing json * CB-4457. Refactor edit, fix icons * CB-4457. Refactor makeDocumentInputValue, created new method for locator * CB-4457 try to get the current metadata for row * CB-4457 clear cache on result update * CB-4457 remove extra check * CB-4457. Fixed npe --------- Co-authored-by: DenisSinelnikov <denis.sinelnikov@dbaever.com> Co-authored-by: naumov <iamemptyhuh@gmail.com> Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com> Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
This commit is contained in:
co-authored by
DenisSinelnikov
naumov
Aleksei Potsetsuev
Daria Marutkina
parent
eea72bd467
commit
cb897343bd
@@ -93,6 +93,11 @@ type SQLResultColumn {
|
||||
supportedOperations: [DataTypeLogicalOperation!]!
|
||||
}
|
||||
|
||||
type SQLResultRowMetaData {
|
||||
data: [Object]!
|
||||
metaData: Object
|
||||
}
|
||||
|
||||
type DatabaseDocument {
|
||||
id: String
|
||||
contentType: String
|
||||
@@ -103,7 +108,8 @@ type DatabaseDocument {
|
||||
type SQLResultSet {
|
||||
id: ID!
|
||||
columns: [ SQLResultColumn ]
|
||||
rows: [ [ Object ] ]
|
||||
rows: [ [ Object ] ] @deprecated
|
||||
rowsWithMetaData: [SQLResultRowMetaData]
|
||||
|
||||
# True means that resultset was generated by single entity query
|
||||
# New rows can be added, old rows can be deleted
|
||||
@@ -112,6 +118,8 @@ type SQLResultSet {
|
||||
hasMoreData: Boolean!
|
||||
# can't update data or load LOB file if hasRowIdentifier = false
|
||||
hasRowIdentifier: Boolean!
|
||||
hasChildrenCollection: Boolean!
|
||||
isSupportsDataFilter: Boolean!
|
||||
}
|
||||
|
||||
type SQLQueryResults {
|
||||
@@ -144,6 +152,12 @@ type SQLExecuteInfo {
|
||||
input SQLResultRow {
|
||||
data: [ Object ]!
|
||||
updateValues: Object
|
||||
metaData: Object
|
||||
}
|
||||
|
||||
input SQLResultRowMetaDataInput {
|
||||
data: [Object]
|
||||
metaData: Object!
|
||||
}
|
||||
|
||||
type DataTypeLogicalOperation {
|
||||
@@ -386,4 +400,5 @@ extend type Mutation {
|
||||
): AsyncTaskInfo!
|
||||
|
||||
asyncSqlRowDataCountResult(taskId: ID!): Int!
|
||||
|
||||
}
|
||||
|
||||
+60
-31
@@ -331,7 +331,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
{
|
||||
// we don't need to add same row several times
|
||||
// (it can be when we update the row from RS with several tables)
|
||||
Set<Object[]> newResultSetRows = new LinkedHashSet<>();
|
||||
Set<WebSQLQueryResultSetRow> newResultSetRows = new LinkedHashSet<>();
|
||||
KeyDataReceiver keyReceiver = new KeyDataReceiver(contextInfo.getResults(resultsId));
|
||||
WebSQLResultsInfo resultsInfo = contextInfo.getResults(resultsId);
|
||||
|
||||
@@ -372,7 +372,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
|
||||
totalUpdateCount += statistics.getRowsUpdated();
|
||||
result.setDuration(result.getDuration() + statistics.getExecuteTime());
|
||||
newResultSetRows.add(rowValues);
|
||||
newResultSetRows.add(new WebSQLQueryResultSetRow(rowValues, null));
|
||||
}
|
||||
|
||||
if (txnManager != null && txnManager.isSupportsTransactions()) {
|
||||
@@ -399,7 +399,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
WebSQLQueryResults updateResults = new WebSQLQueryResults(webSession, dataFormat);
|
||||
updateResults.setUpdateRowCount(totalUpdateCount);
|
||||
updateResults.setResultSet(updatedResultSet);
|
||||
updatedResultSet.setRows(newResultSetRows.toArray(new Object[0][]));
|
||||
updatedResultSet.setRows(List.of(newResultSetRows.toArray(new WebSQLQueryResultSetRow[0])));
|
||||
|
||||
queryResults.add(updateResults);
|
||||
|
||||
@@ -410,7 +410,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
|
||||
private void getUpdatedRowsInfo(
|
||||
@NotNull WebSQLResultsInfo resultsInfo,
|
||||
@NotNull Set<Object[]> newResultSetRows,
|
||||
@NotNull Set<WebSQLQueryResultSetRow> newResultSetRows,
|
||||
@Nullable WebDataFormat dataFormat,
|
||||
@NotNull DBRProgressMonitor monitor)
|
||||
throws DBCException {
|
||||
@@ -420,8 +420,8 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
"Refresh row(s) after insert/update")
|
||||
) {
|
||||
boolean canRefreshResults = resultsInfo.canRefreshResults();
|
||||
for (Object[] row : newResultSetRows) {
|
||||
if (row.length == 0) {
|
||||
for (WebSQLQueryResultSetRow row : newResultSetRows) {
|
||||
if (row.getData().length == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!canRefreshResults) {
|
||||
@@ -438,7 +438,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
if (attr.getRowIdentifier() == null) {
|
||||
continue;
|
||||
}
|
||||
final Object keyValue = row[attr.getOrdinalPosition()];
|
||||
final Object keyValue = row.getData()[attr.getOrdinalPosition()];
|
||||
if (DBUtils.isNullValue(keyValue)) {
|
||||
hasKey = false;
|
||||
break;
|
||||
@@ -455,7 +455,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
}
|
||||
DBDDataFilter filter = new DBDDataFilter(constraints);
|
||||
DBSDataContainer dataContainer = resultsInfo.getDataContainer();
|
||||
WebRowDataReceiver dataReceiver = new WebRowDataReceiver(resultsInfo.getAttributes(), row, dataFormat);
|
||||
WebRowDataReceiver dataReceiver = new WebRowDataReceiver(resultsInfo.getAttributes(), row.getData(), dataFormat);
|
||||
dataContainer.readData(
|
||||
new AbstractExecutionSource(dataContainer, getExecutionContext(dataContainer), this),
|
||||
session,
|
||||
@@ -471,14 +471,14 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
|
||||
private void makeWebCellRow(
|
||||
@NotNull WebSQLResultsInfo resultsInfo,
|
||||
@NotNull Object[] row,
|
||||
@NotNull WebSQLQueryResultSetRow row,
|
||||
@Nullable WebDataFormat dataFormat
|
||||
) throws DBCException {
|
||||
for (int i = 0; i < row.length; i++) {
|
||||
row[i] = WebSQLUtils.makeWebCellValue(
|
||||
for (int i = 0; i < row.getData().length; i++) {
|
||||
row.getData()[i] = WebSQLUtils.makeWebCellValue(
|
||||
webSession,
|
||||
resultsInfo.getAttributeByPosition(i),
|
||||
row[i],
|
||||
row.getData()[i],
|
||||
dataFormat);
|
||||
}
|
||||
}
|
||||
@@ -563,6 +563,14 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
Map<String, Object> updateValues = row.getUpdateValues().entrySet().stream()
|
||||
.filter(x -> CommonUtils.equalObjects(allAttributes[CommonUtils.toInt(x.getKey())].getRowIdentifier(), rowIdentifier))
|
||||
.collect(HashMap::new, (m,v) -> m.put(v.getKey(), v.getValue()), HashMap::putAll);
|
||||
|
||||
Map<String, Object> metaData;
|
||||
if (row.getMetaData() != null) {
|
||||
metaData = new HashMap<>(row.getMetaData());
|
||||
} else {
|
||||
metaData = new HashMap<>();
|
||||
}
|
||||
|
||||
if (finalRow.length == 0 || CommonUtils.isEmpty(updateValues)) {
|
||||
continue;
|
||||
}
|
||||
@@ -582,7 +590,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
boolean isDocumentValue = keyAttributes.length == 1 && keyAttribute.getDataKind() == DBPDataKind.DOCUMENT && dataContainer instanceof DBSDocumentLocator;
|
||||
if (isDocumentValue) {
|
||||
rowValues[updateAttributes.length + i] =
|
||||
makeDocumentInputValue(session, (DBSDocumentLocator) dataContainer, resultsInfo, row);
|
||||
makeDocumentInputValue(session, (DBSDocumentLocator) dataContainer, resultsInfo, row, metaData);
|
||||
} else {
|
||||
rowValues[updateAttributes.length + i] = keyAttribute.getValueHandler().getValueFromObject(
|
||||
session,
|
||||
@@ -651,6 +659,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
if (keyAttributes.length > 0 && !CommonUtils.isEmpty(deletedRows)) {
|
||||
for (WebSQLResultsRow row : deletedRows) {
|
||||
Object[] keyData = row.getData();
|
||||
Map<String, Object> keyMetaData = row.getMetaData();
|
||||
if (keyData.length == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -658,20 +667,37 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
|
||||
boolean isDocumentKey = keyAttributes.length == 1 && keyAttributes[0].getDataKind() == DBPDataKind.DOCUMENT;
|
||||
|
||||
for (int i = 0; i < allAttributes.length; i++) {
|
||||
if (isDocumentKey || ArrayUtils.contains(keyAttributes, allAttributes[i])) {
|
||||
Object realCellValue = convertInputCellValue(session, allAttributes[i],
|
||||
keyData[i], withoutExecution);
|
||||
delKeyAttributes.put(allAttributes[i], realCellValue);
|
||||
if (dataContainer instanceof DBSDocumentLocator dataLocator) {
|
||||
Map<String, Object> keyMap = new LinkedHashMap<>();
|
||||
DBDAttributeBinding[] attributes = resultsInfo.getAttributes();
|
||||
for (int j = 0; j < attributes.length; j++) {
|
||||
DBDAttributeBinding attr = attributes[j];
|
||||
Object plainValue = WebSQLUtils.makePlainCellValue(session, attr, row.getData()[j]);
|
||||
keyMap.put(attr.getName(), plainValue);
|
||||
}
|
||||
}
|
||||
DBDDocument document = dataLocator.findDocument(session, keyMap, keyMetaData);
|
||||
|
||||
DBSDataManipulator.ExecuteBatch deleteBatch = dataManipulator.deleteData(
|
||||
session,
|
||||
delKeyAttributes.keySet().toArray(new DBSAttributeBase[0]),
|
||||
executionSource);
|
||||
deleteBatch.add(delKeyAttributes.values().toArray());
|
||||
resultBatches.put(deleteBatch, new Object[0]);
|
||||
DBSDataManipulator.ExecuteBatch deleteBatch = dataManipulator.deleteData(
|
||||
session,
|
||||
keyAttributes,
|
||||
executionSource);
|
||||
deleteBatch.add(new Object[] {document});
|
||||
resultBatches.put(deleteBatch, new Object[0]);
|
||||
} else {
|
||||
for (int i = 0; i < allAttributes.length; i++) {
|
||||
if (isDocumentKey || ArrayUtils.contains(keyAttributes, allAttributes[i])) {
|
||||
Object realCellValue = convertInputCellValue(session, allAttributes[i],
|
||||
keyData[i], withoutExecution);
|
||||
delKeyAttributes.put(allAttributes[i], realCellValue);
|
||||
}
|
||||
}
|
||||
DBSDataManipulator.ExecuteBatch deleteBatch = dataManipulator.deleteData(
|
||||
session,
|
||||
delKeyAttributes.keySet().toArray(new DBSAttributeBase[0]),
|
||||
executionSource);
|
||||
deleteBatch.add(delKeyAttributes.values().toArray());
|
||||
resultBatches.put(deleteBatch, new Object[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -693,7 +719,8 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
DBCSession session,
|
||||
DBSDocumentLocator dataContainer,
|
||||
WebSQLResultsInfo resultsInfo,
|
||||
WebSQLResultsRow row) throws DBException
|
||||
WebSQLResultsRow row,
|
||||
Map<String, Object> metaData) throws DBException
|
||||
{
|
||||
// Document reference
|
||||
DBDDocument document = null;
|
||||
@@ -702,16 +729,18 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
for (int j = 0; j < attributes.length; j++) {
|
||||
DBDAttributeBinding attr = attributes[j];
|
||||
Object plainValue = WebSQLUtils.makePlainCellValue(session, attr, row.getData()[j]);
|
||||
if (plainValue instanceof DBDDocument) {
|
||||
if (plainValue instanceof DBDDocument dbdDocument) {
|
||||
// FIXME: Hack for DynamoDB. We pass entire document as a key
|
||||
// FIXME: Let's just return it back for now
|
||||
document = (DBDDocument) plainValue;
|
||||
break;
|
||||
if (dataContainer.isDocumentValid(dbdDocument)) {
|
||||
document = (DBDDocument) plainValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
keyMap.put(attr.getName(), plainValue);
|
||||
}
|
||||
if (document == null) {
|
||||
document = dataContainer.findDocument(session.getProgressMonitor(), keyMap);
|
||||
document = dataContainer.findDocument(session, keyMap, metaData);
|
||||
if (document == null) {
|
||||
throw new DBCException("Error finding document by key " + keyMap);
|
||||
}
|
||||
@@ -826,7 +855,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
boolean isDocumentValue = keyAttributes.length == 1 && keyAttribute.getDataKind() == DBPDataKind.DOCUMENT && dataContainer instanceof DBSDocumentLocator;
|
||||
if (isDocumentValue) {
|
||||
rowValues[i] =
|
||||
makeDocumentInputValue(session, (DBSDocumentLocator) dataContainer, resultsInfo, row);
|
||||
makeDocumentInputValue(session, (DBSDocumentLocator) dataContainer, resultsInfo, row, null);
|
||||
} else {
|
||||
Object inputCellValue = row.getData()[keyAttribute.getOrdinalPosition()];
|
||||
|
||||
|
||||
+30
-12
@@ -25,13 +25,15 @@ import org.jkiss.dbeaver.model.DBUtils;
|
||||
import org.jkiss.dbeaver.model.data.*;
|
||||
import org.jkiss.dbeaver.model.exec.*;
|
||||
import org.jkiss.dbeaver.model.impl.data.DBDValueError;
|
||||
import org.jkiss.dbeaver.model.meta.MetaData;
|
||||
import org.jkiss.dbeaver.model.sql.DBQuotaException;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntity;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
private static final Log log = Log.getLog(WebSQLQueryDataReceiver.class);
|
||||
@@ -42,7 +44,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
private final WebSQLQueryResultSet webResultSet = new WebSQLQueryResultSet();
|
||||
|
||||
private DBDAttributeBinding[] bindings;
|
||||
private List<Object[]> rows = new ArrayList<>();
|
||||
private List<WebSQLQueryResultSetRow> rows = new ArrayList<>();
|
||||
private final Number rowLimit;
|
||||
|
||||
WebSQLQueryDataReceiver(WebSQLContextInfo contextInfo, DBSDataContainer dataContainer, WebDataFormat dataFormat) {
|
||||
@@ -70,6 +72,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
@Override
|
||||
public void fetchRow(DBCSession session, DBCResultSet resultSet) throws DBCException {
|
||||
|
||||
Map<String, Object> metaDataMap = null;
|
||||
Object[] row = new Object[bindings.length];
|
||||
|
||||
for (int i = 0; i < bindings.length; i++) {
|
||||
@@ -81,12 +84,25 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
binding.getMetaAttribute(),
|
||||
i);
|
||||
row[i] = cellValue;
|
||||
if (cellValue != null) {
|
||||
Method[] methods = cellValue.getClass().getMethods();
|
||||
for (Method method : methods) {
|
||||
if (method.isAnnotationPresent(MetaData.class)) {
|
||||
if (metaDataMap == null) {
|
||||
metaDataMap = new HashMap<>();
|
||||
}
|
||||
Object value = method.invoke(cellValue);
|
||||
metaDataMap.put(method.getAnnotation(MetaData.class).name(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Throwable e) {
|
||||
row[i] = new DBDValueError(e);
|
||||
}
|
||||
}
|
||||
|
||||
rows.add(row);
|
||||
rows.add(new WebSQLQueryResultSetRow(row, metaDataMap));
|
||||
|
||||
if (rowLimit != null && rows.size() > rowLimit.longValue()) {
|
||||
throw new DBQuotaException(
|
||||
@@ -101,7 +117,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
DBSEntity entity = dataContainer instanceof DBSEntity ? (DBSEntity) dataContainer : null;
|
||||
|
||||
try {
|
||||
DBExecUtils.bindAttributes(session, entity, resultSet, bindings, rows);
|
||||
DBExecUtils.bindAttributes(session, entity, resultSet, bindings, rows.stream().map(WebSQLQueryResultSetRow::getData).collect(Collectors.toList()));
|
||||
} catch (DBException e) {
|
||||
log.error("Error binding attributes", e);
|
||||
}
|
||||
@@ -122,15 +138,17 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
}
|
||||
|
||||
// Convert row values
|
||||
for (Object[] row : rows) {
|
||||
for (WebSQLQueryResultSetRow row : rows) {
|
||||
for (int i = 0; i < bindings.length; i++) {
|
||||
DBDAttributeBinding binding = bindings[i];
|
||||
row[i] = WebSQLUtils.makeWebCellValue(webSession, binding, row[i], dataFormat);
|
||||
row.getData()[i] = WebSQLUtils.makeWebCellValue(webSession, binding, row.getData()[i], dataFormat);
|
||||
}
|
||||
}
|
||||
|
||||
webResultSet.setColumns(bindings);
|
||||
webResultSet.setRows(rows.toArray(new Object[0][]));
|
||||
webResultSet.setRows(List.of(rows.toArray(new WebSQLQueryResultSetRow[0])));
|
||||
webResultSet.setHasChildrenCollection(resultSet instanceof DBDSubCollectionResultSet);
|
||||
webResultSet.setSupportsDataFilter(dataContainer.isFeatureSupported(DBSDataContainer.FEATURE_DATA_FILTER));
|
||||
|
||||
WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, bindings);
|
||||
webResultSet.setResultsInfo(resultsInfo);
|
||||
@@ -157,14 +175,14 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
// Convert original rows into new rows with leaf attributes
|
||||
// Extract values for leaf attributes from original row
|
||||
DBDAttributeBinding[] leafAttributes = leafBindings.toArray(new DBDAttributeBinding[0]);
|
||||
List<Object[]> newRows = new ArrayList<>();
|
||||
for (Object[] row : rows) {
|
||||
List<WebSQLQueryResultSetRow> newRows = new ArrayList<>();
|
||||
for (WebSQLQueryResultSetRow row : rows) {
|
||||
Object[] newRow = new Object[leafBindings.size()];
|
||||
for (int i = 0; i < leafBindings.size(); i++) {
|
||||
DBDAttributeBinding leafAttr = leafBindings.get(i);
|
||||
try {
|
||||
//Object topValue = row[leafAttr.getTopParent().getOrdinalPosition()];
|
||||
Object cellValue = DBUtils.getAttributeValue(leafAttr, leafAttributes, row);
|
||||
Object cellValue = DBUtils.getAttributeValue(leafAttr, leafAttributes, row.getData());
|
||||
/*
|
||||
Object cellValue = leafAttr.getValueHandler().getValueFromObject(
|
||||
session,
|
||||
@@ -178,7 +196,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
newRow[i] = new DBDValueError(e);
|
||||
}
|
||||
}
|
||||
newRows.add(newRow);
|
||||
newRows.add(new WebSQLQueryResultSetRow(newRow, row.getMetaData()));
|
||||
}
|
||||
this.bindings = leafAttributes;
|
||||
this.rows = newRows;
|
||||
|
||||
+34
-2
@@ -19,6 +19,11 @@ package io.cloudbeaver.service.sql;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.utils.Pair;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Web SQL query resultset.
|
||||
@@ -28,12 +33,15 @@ public class WebSQLQueryResultSet {
|
||||
private static final Log log = Log.getLog(WebSQLQueryResultSet.class);
|
||||
|
||||
private WebSQLQueryResultColumn[] columns;
|
||||
private Object[][] rows;
|
||||
private List<WebSQLQueryResultSetRow> rows;
|
||||
private boolean hasMoreData;
|
||||
private WebSQLResultsInfo resultsInfo;
|
||||
private boolean singleEntity = true;
|
||||
private boolean hasRowIdentifier;
|
||||
|
||||
private boolean hasChildrenCollection;
|
||||
private boolean isSupportsDataFilter;
|
||||
|
||||
public WebSQLQueryResultSet() {
|
||||
}
|
||||
|
||||
@@ -60,11 +68,17 @@ public class WebSQLQueryResultSet {
|
||||
}
|
||||
|
||||
@Property
|
||||
@Deprecated
|
||||
public Object[][] getRows() {
|
||||
return rows.stream().map(WebSQLQueryResultSetRow::getData).toArray(x -> new Object[x][1]);
|
||||
}
|
||||
|
||||
@Property
|
||||
public List<WebSQLQueryResultSetRow> getRowsWithMetaData() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void setRows(Object[][] rows) {
|
||||
public void setRows(List<WebSQLQueryResultSetRow> rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
@@ -102,4 +116,22 @@ public class WebSQLQueryResultSet {
|
||||
public void setHasRowIdentifier(boolean hasRowIdentifier) {
|
||||
this.hasRowIdentifier = hasRowIdentifier;
|
||||
}
|
||||
|
||||
@Property
|
||||
public boolean isHasChildrenCollection() {
|
||||
return hasChildrenCollection;
|
||||
}
|
||||
|
||||
public void setHasChildrenCollection(boolean hasSuCollection) {
|
||||
this.hasChildrenCollection = hasSuCollection;
|
||||
}
|
||||
|
||||
@Property
|
||||
public boolean isSupportsDataFilter() {
|
||||
return isSupportsDataFilter;
|
||||
}
|
||||
|
||||
public void setSupportsDataFilter(boolean supportsDataFilter) {
|
||||
isSupportsDataFilter = supportsDataFilter;
|
||||
}
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class WebSQLQueryResultSetRow {
|
||||
|
||||
private Object[] data;
|
||||
|
||||
private Map<String, Object> metaData;
|
||||
|
||||
public WebSQLQueryResultSetRow(Object[] data, Map<String, Object> metaData) {
|
||||
this.data = data;
|
||||
this.metaData = metaData;
|
||||
}
|
||||
|
||||
public Object[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public Map<String, Object> getMetaData() {
|
||||
return metaData;
|
||||
}
|
||||
|
||||
public void setData(Object[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setMetaData(Map<String, Object> metaData) {
|
||||
this.metaData = metaData;
|
||||
}
|
||||
}
|
||||
+8
-6
@@ -25,9 +25,11 @@ import org.jkiss.dbeaver.model.DBPDataKind;
|
||||
import org.jkiss.dbeaver.model.data.DBDDocument;
|
||||
import org.jkiss.dbeaver.model.exec.DBCException;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.utils.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Web SQL query results.
|
||||
@@ -86,16 +88,16 @@ public class WebSQLQueryResults {
|
||||
}
|
||||
|
||||
List<WebSQLDatabaseDocument> documents = new ArrayList<>();
|
||||
for (Object[] row : resultSet.getRows()) {
|
||||
if (row.length != 1) {
|
||||
for (WebSQLQueryResultSetRow row : resultSet.getRowsWithMetaData()) {
|
||||
if (row.getData().length != 1) {
|
||||
log.debug("Non-document row content");
|
||||
}
|
||||
if (row[0] == null) {
|
||||
if (row.getData()[0] == null) {
|
||||
documents.add(null);
|
||||
} else if (row[0] instanceof DBDDocument) {
|
||||
documents.add(new WebSQLDatabaseDocument(webSession, (DBDDocument) row[0]));
|
||||
} else if (row.getData()[0] instanceof DBDDocument) {
|
||||
documents.add(new WebSQLDatabaseDocument(webSession, (DBDDocument) row.getData()[0]));
|
||||
} else {
|
||||
log.debug("Non-document row value: " + row[0].getClass().getName());
|
||||
log.debug("Non-document row value: " + row.getData()[0].getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -28,12 +29,16 @@ public class WebSQLResultsRow {
|
||||
private Object[] data;
|
||||
private Map<String, Object> updateValues;
|
||||
|
||||
@Nullable
|
||||
private Map<String, Object> metaData;
|
||||
|
||||
public WebSQLResultsRow() {
|
||||
}
|
||||
|
||||
public WebSQLResultsRow(Map<String, Object> map) {
|
||||
data = JSONUtils.getObjectList(map, "data").toArray();
|
||||
updateValues = JSONUtils.getObject(map, "updateValues");
|
||||
metaData = JSONUtils.getObject(map, "metaData");
|
||||
}
|
||||
|
||||
public Object[] getData() {
|
||||
@@ -43,4 +48,9 @@ public class WebSQLResultsRow {
|
||||
public Map<String, Object> getUpdateValues() {
|
||||
return updateValues;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, Object> getMetaData() {
|
||||
return metaData;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-6
@@ -33,9 +33,7 @@ import org.jkiss.dbeaver.model.DBPDataSource;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.DBUtils;
|
||||
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
|
||||
import org.jkiss.dbeaver.model.exec.DBCException;
|
||||
import org.jkiss.dbeaver.model.exec.DBCLogicalOperator;
|
||||
import org.jkiss.dbeaver.model.exec.DBExecUtils;
|
||||
import org.jkiss.dbeaver.model.exec.*;
|
||||
import org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNNode;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
@@ -50,6 +48,7 @@ import org.jkiss.dbeaver.model.sql.parser.SQLScriptParser;
|
||||
import org.jkiss.dbeaver.model.sql.registry.SQLGeneratorConfigurationRegistry;
|
||||
import org.jkiss.dbeaver.model.sql.registry.SQLGeneratorDescriptor;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntity;
|
||||
import org.jkiss.dbeaver.model.struct.DBSObject;
|
||||
import org.jkiss.dbeaver.model.struct.DBSWrapper;
|
||||
import org.jkiss.dbeaver.utils.RuntimeUtils;
|
||||
@@ -60,9 +59,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,46 +1,47 @@
|
||||
mutation getSqlExecuteTaskResults(
|
||||
$taskId: ID!
|
||||
) {
|
||||
result: asyncSqlExecuteResults(
|
||||
taskId: $taskId
|
||||
) {
|
||||
duration
|
||||
statusMessage
|
||||
filterText
|
||||
fullQuery
|
||||
results {
|
||||
title
|
||||
updateRowCount
|
||||
sourceQuery
|
||||
dataFormat
|
||||
resultSet {
|
||||
id
|
||||
columns {
|
||||
dataKind
|
||||
entityName
|
||||
fullTypeName
|
||||
icon
|
||||
label
|
||||
maxLength
|
||||
name
|
||||
position
|
||||
precision
|
||||
required
|
||||
readOnly
|
||||
readOnlyStatus
|
||||
scale
|
||||
typeName
|
||||
supportedOperations {
|
||||
id
|
||||
expression
|
||||
argumentCount
|
||||
}
|
||||
}
|
||||
rows
|
||||
singleEntity
|
||||
hasMoreData
|
||||
hasRowIdentifier
|
||||
}
|
||||
mutation getSqlExecuteTaskResults($taskId: ID!) {
|
||||
result: asyncSqlExecuteResults(taskId: $taskId) {
|
||||
duration
|
||||
statusMessage
|
||||
filterText
|
||||
fullQuery
|
||||
results {
|
||||
title
|
||||
updateRowCount
|
||||
sourceQuery
|
||||
dataFormat
|
||||
resultSet {
|
||||
id
|
||||
columns {
|
||||
dataKind
|
||||
entityName
|
||||
fullTypeName
|
||||
icon
|
||||
label
|
||||
maxLength
|
||||
name
|
||||
position
|
||||
precision
|
||||
required
|
||||
readOnly
|
||||
readOnlyStatus
|
||||
scale
|
||||
typeName
|
||||
supportedOperations {
|
||||
id
|
||||
expression
|
||||
argumentCount
|
||||
}
|
||||
}
|
||||
rowsWithMetaData {
|
||||
data
|
||||
metaData
|
||||
}
|
||||
singleEntity
|
||||
hasMoreData
|
||||
hasRowIdentifier
|
||||
isSupportsDataFilter
|
||||
hasChildrenCollection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,38 @@
|
||||
mutation updateResultsDataBatch(
|
||||
$projectId: ID!
|
||||
$connectionId: ID!
|
||||
$contextId: ID!
|
||||
$resultsId: ID!
|
||||
$updatedRows: [ SQLResultRow! ]
|
||||
$deletedRows: [ SQLResultRow! ]
|
||||
$addedRows: [ SQLResultRow! ]
|
||||
$projectId: ID!
|
||||
$connectionId: ID!
|
||||
$contextId: ID!
|
||||
$resultsId: ID!
|
||||
$updatedRows: [SQLResultRow!]
|
||||
$deletedRows: [SQLResultRow!]
|
||||
$addedRows: [SQLResultRow!]
|
||||
) {
|
||||
result: updateResultsDataBatch(
|
||||
projectId: $projectId
|
||||
connectionId: $connectionId
|
||||
contextId: $contextId
|
||||
resultsId: $resultsId
|
||||
result: updateResultsDataBatch(
|
||||
projectId: $projectId
|
||||
connectionId: $connectionId
|
||||
contextId: $contextId
|
||||
resultsId: $resultsId
|
||||
|
||||
updatedRows: $updatedRows
|
||||
deletedRows: $deletedRows
|
||||
addedRows: $addedRows
|
||||
) {
|
||||
duration
|
||||
filterText
|
||||
results {
|
||||
updateRowCount
|
||||
resultSet {
|
||||
id
|
||||
rows
|
||||
singleEntity
|
||||
hasMoreData
|
||||
hasRowIdentifier
|
||||
}
|
||||
updatedRows: $updatedRows
|
||||
deletedRows: $deletedRows
|
||||
addedRows: $addedRows
|
||||
) {
|
||||
duration
|
||||
filterText
|
||||
results {
|
||||
updateRowCount
|
||||
resultSet {
|
||||
id
|
||||
rowsWithMetaData {
|
||||
data
|
||||
metaData
|
||||
}
|
||||
singleEntity
|
||||
hasMoreData
|
||||
hasRowIdentifier
|
||||
isSupportsDataFilter
|
||||
hasChildrenCollection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +255,8 @@ export class ContainerDataSource extends ResultSetDataSource<IDataContainerOptio
|
||||
contextId: executionContextInfo.id,
|
||||
dataFormat: result.dataFormat!,
|
||||
updateRowCount: result.updateRowCount || 0,
|
||||
loadedFully: (result.resultSet?.rows?.length || 0) < limit,
|
||||
count: result.resultSet?.rows?.length || 0,
|
||||
loadedFully: (result.resultSet?.rowsWithMetaData?.length || 0) < limit,
|
||||
count: result.resultSet?.rowsWithMetaData?.length || 0,
|
||||
totalCount: null,
|
||||
data: result.resultSet,
|
||||
}));
|
||||
|
||||
@@ -36,8 +36,8 @@ export class DataViewerTableService {
|
||||
return this.tableViewerStorageService.has(tableId);
|
||||
}
|
||||
|
||||
get(modelId: string): IDatabaseDataModel<any, any> | undefined {
|
||||
return this.tableViewerStorageService.get(modelId);
|
||||
get(tableId: string): IDatabaseDataModel<any, any> | undefined {
|
||||
return this.tableViewerStorageService.get(tableId);
|
||||
}
|
||||
|
||||
async removeTableModel(tableId: string): Promise<void> {
|
||||
|
||||
+13
-4
@@ -21,11 +21,11 @@ export class DocumentDataAction extends DatabaseDataResultAction<IDocumentElemen
|
||||
static dataFormat = [ResultDataFormat.Document];
|
||||
|
||||
get documents(): IDatabaseDataDocument[] {
|
||||
return this.result.data?.rows?.map(row => row[0]) || [];
|
||||
return this.result.data?.rowsWithMetaData?.map(row => row.data[0]) || [];
|
||||
}
|
||||
|
||||
get count(): number {
|
||||
return this.result.data?.rows?.length || 0;
|
||||
return this.result.data?.rowsWithMetaData?.length || 0;
|
||||
}
|
||||
|
||||
constructor(source: IDatabaseDataSource<any, IDatabaseResultSet>) {
|
||||
@@ -37,6 +37,11 @@ export class DocumentDataAction extends DatabaseDataResultAction<IDocumentElemen
|
||||
});
|
||||
}
|
||||
|
||||
getMetadataForDocument(documentId: string) {
|
||||
const row = this.result.data?.rowsWithMetaData?.find(row => row.data[0]?.id === documentId);
|
||||
return row?.metaData;
|
||||
}
|
||||
|
||||
getIdentifier(key: IDocumentElementKey): string {
|
||||
return key.index.toString();
|
||||
}
|
||||
@@ -54,8 +59,12 @@ export class DocumentDataAction extends DatabaseDataResultAction<IDocumentElemen
|
||||
}
|
||||
|
||||
set(index: number, value: IDatabaseDataDocument): void {
|
||||
if (this.result.data?.rows) {
|
||||
this.result.data.rows[index][0] = value;
|
||||
if (this.result.data?.rowsWithMetaData) {
|
||||
const row = this.result.data.rowsWithMetaData[index];
|
||||
|
||||
if (row.data) {
|
||||
row.data[0] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -125,7 +125,8 @@ export class DocumentEditAction extends DatabaseEditAction<IDocumentElementKey,
|
||||
let rowIndex = 0;
|
||||
|
||||
for (const [id, document] of this.editedElements) {
|
||||
const value = result.data?.rows?.[rowIndex];
|
||||
const row = result.data?.rowsWithMetaData?.[rowIndex];
|
||||
const value = row?.data;
|
||||
|
||||
if (value !== undefined) {
|
||||
this.data.set(id, value[0]);
|
||||
@@ -138,7 +139,8 @@ export class DocumentEditAction extends DatabaseEditAction<IDocumentElementKey,
|
||||
let rowIndex = 0;
|
||||
|
||||
for (const [id, document] of this.editedElements) {
|
||||
const value = result.data?.rows?.[rowIndex];
|
||||
const row = result.data?.rowsWithMetaData?.[rowIndex];
|
||||
const value = row?.data;
|
||||
|
||||
if (value !== undefined) {
|
||||
this.data.set(id, value[0]);
|
||||
@@ -179,6 +181,7 @@ export class DocumentEditAction extends DatabaseEditAction<IDocumentElementKey,
|
||||
|
||||
updatedRows.push({
|
||||
data: [this.data.get(id)],
|
||||
metaData: this.data.getMetadataForDocument(document.id),
|
||||
updateValues: {
|
||||
// TODO: remove, place new document in data field
|
||||
0: document,
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import type { IDatabaseDataAction } from '../IDatabaseDataAction';
|
||||
import type { IDatabaseDataResult } from '../IDatabaseDataResult';
|
||||
|
||||
export interface IDatabaseDataCacheAction<TKey, TResult extends IDatabaseDataResult> extends IDatabaseDataAction<any, TResult> {
|
||||
has(key: TKey, scope: symbol): boolean;
|
||||
get<T>(key: TKey, scope: symbol): T | undefined;
|
||||
set<T>(key: TKey, scope: symbol, value: T): void;
|
||||
delete(key: TKey, scope: symbol): void;
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { makeObservable, observable } from 'mobx';
|
||||
|
||||
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { DatabaseDataAction } from '../../DatabaseDataAction';
|
||||
import type { IDatabaseDataSource } from '../../IDatabaseDataSource';
|
||||
import type { IDatabaseResultSet } from '../../IDatabaseResultSet';
|
||||
import { databaseDataAction } from '../DatabaseDataActionDecorator';
|
||||
import type { IDatabaseDataCacheAction } from '../IDatabaseDataCacheAction';
|
||||
import type { IResultSetElementKey, IResultSetRowKey } from './IResultSetDataKey';
|
||||
import { ResultSetDataAction } from './ResultSetDataAction';
|
||||
|
||||
@databaseDataAction()
|
||||
export class ResultSetCacheAction
|
||||
extends DatabaseDataAction<any, IDatabaseResultSet>
|
||||
implements IDatabaseDataCacheAction<IResultSetElementKey, IDatabaseResultSet>
|
||||
{
|
||||
static dataFormat = [ResultDataFormat.Resultset];
|
||||
|
||||
private readonly cache: Map<string, Map<symbol, any>>;
|
||||
|
||||
constructor(source: IDatabaseDataSource<any, IDatabaseResultSet>, private readonly data: ResultSetDataAction) {
|
||||
super(source);
|
||||
|
||||
this.cache = new Map();
|
||||
|
||||
makeObservable<this, 'cache'>(this, {
|
||||
cache: observable,
|
||||
});
|
||||
}
|
||||
|
||||
get<T>(key: IResultSetElementKey, scope: symbol): T | undefined {
|
||||
const keyCache = this.getKeyCache(key);
|
||||
if (!keyCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
return keyCache.get(scope);
|
||||
}
|
||||
|
||||
getRow<T>(key: IResultSetRowKey, scope: symbol): T | undefined {
|
||||
const keyCache = this.getRowCache(key);
|
||||
if (!keyCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
return keyCache.get(scope);
|
||||
}
|
||||
|
||||
has(key: IResultSetElementKey, scope: symbol) {
|
||||
const keyCache = this.getKeyCache(key);
|
||||
|
||||
if (!keyCache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return keyCache.has(scope);
|
||||
}
|
||||
|
||||
hasRow(key: IResultSetRowKey, scope: symbol) {
|
||||
const keyCache = this.getRowCache(key);
|
||||
|
||||
if (!keyCache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return keyCache.has(scope);
|
||||
}
|
||||
|
||||
set<T>(key: IResultSetElementKey, scope: symbol, value: T) {
|
||||
const keyCache = this.getOrCreateKeyCache(key);
|
||||
|
||||
keyCache.set(scope, value);
|
||||
}
|
||||
|
||||
setRow<T>(key: IResultSetRowKey, scope: symbol, value: T) {
|
||||
const keyCache = this.getOrCreateRowKeyCache(key);
|
||||
|
||||
keyCache.set(scope, value);
|
||||
}
|
||||
|
||||
delete(key: IResultSetElementKey, scope: symbol) {
|
||||
const keyCache = this.getKeyCache(key);
|
||||
|
||||
if (keyCache) {
|
||||
keyCache.delete(scope);
|
||||
}
|
||||
}
|
||||
|
||||
deleteRow(key: IResultSetRowKey, scope: symbol) {
|
||||
const keyCache = this.getRowCache(key);
|
||||
|
||||
if (keyCache) {
|
||||
keyCache.delete(scope);
|
||||
}
|
||||
}
|
||||
|
||||
afterResultUpdate() {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
private serializeRowKey(key: IResultSetRowKey) {
|
||||
return 'row:' + this.data.serializeRowKey(key);
|
||||
}
|
||||
|
||||
private serializeKey(key: IResultSetElementKey) {
|
||||
return this.data.serialize(key);
|
||||
}
|
||||
|
||||
private getKeyCache(key: IResultSetElementKey) {
|
||||
return this.cache.get(this.serializeKey(key));
|
||||
}
|
||||
|
||||
private getRowCache(key: IResultSetRowKey) {
|
||||
return this.cache.get(this.serializeRowKey(key));
|
||||
}
|
||||
|
||||
private getOrCreateKeyCache(key: IResultSetElementKey) {
|
||||
let keyCache = this.getKeyCache(key);
|
||||
|
||||
if (!keyCache) {
|
||||
keyCache = observable(new Map());
|
||||
this.cache.set(this.serializeKey(key), keyCache);
|
||||
}
|
||||
|
||||
return keyCache;
|
||||
}
|
||||
|
||||
private getOrCreateRowKeyCache(key: IResultSetRowKey) {
|
||||
let keyCache = this.getRowCache(key);
|
||||
|
||||
if (!keyCache) {
|
||||
keyCache = observable(new Map());
|
||||
this.cache.set(this.serializeRowKey(key), keyCache);
|
||||
}
|
||||
|
||||
return keyCache;
|
||||
}
|
||||
}
|
||||
+22
-10
@@ -23,8 +23,8 @@ import type { IResultSetValue } from './ResultSetFormatAction';
|
||||
export class ResultSetDataAction extends DatabaseDataResultAction<IResultSetElementKey, IDatabaseResultSet> {
|
||||
static dataFormat = [ResultDataFormat.Resultset];
|
||||
|
||||
get rows(): IResultSetValue[][] {
|
||||
return this.result.data?.rows || [];
|
||||
get rows() {
|
||||
return this.result.data?.rowsWithMetaData || [];
|
||||
}
|
||||
|
||||
get columns(): SqlResultColumn[] {
|
||||
@@ -47,6 +47,10 @@ export class ResultSetDataAction extends DatabaseDataResultAction<IResultSetElem
|
||||
return ResultSetDataKeysUtils.serializeElementKey(key);
|
||||
}
|
||||
|
||||
serializeRowKey(key: IResultSetRowKey): string {
|
||||
return ResultSetDataKeysUtils.serialize(key);
|
||||
}
|
||||
|
||||
getDefaultKey(): IResultSetElementKey {
|
||||
return {
|
||||
row: {
|
||||
@@ -60,9 +64,9 @@ export class ResultSetDataAction extends DatabaseDataResultAction<IResultSetElem
|
||||
}
|
||||
|
||||
insertRow(row: IResultSetRowKey, value: IResultSetValue[], shift = 0): IResultSetRowKey | undefined {
|
||||
if (this.result.data?.rows) {
|
||||
if (this.result.data?.rowsWithMetaData) {
|
||||
const index = row.index + shift;
|
||||
this.result.data.rows.splice(index, 0, value);
|
||||
this.result.data.rowsWithMetaData.splice(index, 0, { data: value, metaData: {} });
|
||||
|
||||
return { index, subIndex: 0 };
|
||||
}
|
||||
@@ -71,9 +75,9 @@ export class ResultSetDataAction extends DatabaseDataResultAction<IResultSetElem
|
||||
}
|
||||
|
||||
removeRow(row: IResultSetRowKey, shift = 0): IResultSetRowKey | undefined {
|
||||
if (this.result.data?.rows) {
|
||||
if (this.result.data?.rowsWithMetaData) {
|
||||
const index = row.index + shift;
|
||||
this.result.data.rows.splice(index, 1);
|
||||
this.result.data.rowsWithMetaData.splice(index, 1);
|
||||
|
||||
return { index: index - 1, subIndex: 0 };
|
||||
}
|
||||
@@ -81,8 +85,8 @@ export class ResultSetDataAction extends DatabaseDataResultAction<IResultSetElem
|
||||
}
|
||||
|
||||
setRowValue(row: IResultSetRowKey, value: IResultSetValue[], shift = 0): void {
|
||||
if (this.result.data?.rows) {
|
||||
this.result.data.rows[row.index + shift] = value;
|
||||
if (this.result.data?.rowsWithMetaData) {
|
||||
this.result.data.rowsWithMetaData[row.index + shift] = { data: value, metaData: this.getRowMetadata(row) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +95,15 @@ export class ResultSetDataAction extends DatabaseDataResultAction<IResultSetElem
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.rows[row.index];
|
||||
return this.rows[row.index].data;
|
||||
}
|
||||
|
||||
getRowMetadata(row: IResultSetRowKey) {
|
||||
if (row.index >= this.rows.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.rows[row.index].metaData;
|
||||
}
|
||||
|
||||
getCellValue(cell: IResultSetElementKey): IResultSetValue | undefined {
|
||||
@@ -99,7 +111,7 @@ export class ResultSetDataAction extends DatabaseDataResultAction<IResultSetElem
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.rows[cell.row.index][cell.column.index];
|
||||
return this.rows[cell.row.index].data?.[cell.column.index];
|
||||
}
|
||||
|
||||
getContent(cell: IResultSetElementKey): IResultSetContentValue | null {
|
||||
|
||||
+5
-3
@@ -7,14 +7,16 @@
|
||||
*/
|
||||
import type { IResultSetColumnKey, IResultSetElementKey, IResultSetRowKey } from './IResultSetDataKey';
|
||||
|
||||
export type SerializableKey = IResultSetColumnKey | IResultSetRowKey;
|
||||
|
||||
export const ResultSetDataKeysUtils = {
|
||||
serializeElementKey(elementKey: IResultSetElementKey): string {
|
||||
return this.serialize(elementKey.column) + this.serialize(elementKey.row);
|
||||
return this.serialize(elementKey.column) + '.' + this.serialize(elementKey.row);
|
||||
},
|
||||
isElementsKeyEqual(a: IResultSetElementKey, b: IResultSetElementKey) {
|
||||
return this.isEqual(a.column, b.column) && this.isEqual(a.row, b.row);
|
||||
},
|
||||
serialize(key: IResultSetColumnKey | IResultSetRowKey): string {
|
||||
serialize(key: SerializableKey): string {
|
||||
let base = `${key.index}`;
|
||||
|
||||
if ('subIndex' in key) {
|
||||
@@ -23,7 +25,7 @@ export const ResultSetDataKeysUtils = {
|
||||
|
||||
return base;
|
||||
},
|
||||
isEqual<T extends IResultSetColumnKey | IResultSetRowKey>(a: T, b: T): boolean {
|
||||
isEqual<T extends SerializableKey>(a: T, b: T): boolean {
|
||||
if (a.index !== b.index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+4
-3
@@ -316,7 +316,7 @@ export class ResultSetEditAction extends DatabaseEditAction<IResultSetElementKey
|
||||
}
|
||||
|
||||
applyPartialUpdate(result: IDatabaseResultSet): void {
|
||||
if (result.data?.rows?.length !== this.updates.length) {
|
||||
if (result.data?.rowsWithMetaData?.length !== this.updates.length) {
|
||||
console.warn('ResultSetEditAction: returned data differs from performed update');
|
||||
}
|
||||
|
||||
@@ -340,7 +340,7 @@ export class ResultSetEditAction extends DatabaseEditAction<IResultSetElementKey
|
||||
}, 0);
|
||||
|
||||
for (const update of tempUpdates) {
|
||||
const value = result.data?.rows?.[update.rowIndex];
|
||||
const value = result.data?.rowsWithMetaData?.[update.rowIndex]?.data;
|
||||
const row = update.update.row;
|
||||
const type = update.update.type;
|
||||
|
||||
@@ -498,6 +498,7 @@ export class ResultSetEditAction extends DatabaseEditAction<IResultSetElementKey
|
||||
}
|
||||
return obj;
|
||||
}, {}),
|
||||
metaData: this.data.getRowMetadata(update.row),
|
||||
});
|
||||
}
|
||||
break;
|
||||
@@ -519,7 +520,7 @@ export class ResultSetEditAction extends DatabaseEditAction<IResultSetElementKey
|
||||
}
|
||||
const deletedRows = batch.deletedRows as SqlResultRow[];
|
||||
|
||||
deletedRows.push({ data: replaceBlobsWithNull(update.update) });
|
||||
deletedRows.push({ data: replaceBlobsWithNull(update.update), metaData: this.data.getRowMetadata(update.row) });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ export class ResultSetViewAction extends DatabaseDataAction<any, IDatabaseResult
|
||||
}
|
||||
|
||||
get rows(): IResultSetValue[][] {
|
||||
return this.data.rows;
|
||||
return this.data.rows.map(row => row.data || []);
|
||||
}
|
||||
|
||||
get columns(): SqlResultColumn[] {
|
||||
|
||||
@@ -43,6 +43,7 @@ export * from './DatabaseDataModel/Actions/IDatabaseDataFormatAction';
|
||||
export * from './DatabaseDataModel/Actions/IDatabaseDataMetadataAction';
|
||||
export * from './DatabaseDataModel/Actions/IDatabaseDataResultAction';
|
||||
export * from './DatabaseDataModel/Actions/IDatabaseDataSelectAction';
|
||||
export * from './DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction';
|
||||
export * from './DatabaseDataModel/DatabaseDataAction';
|
||||
export * from './DatabaseDataModel/DatabaseDataActions';
|
||||
export * from './DatabaseDataModel/DatabaseDataFormat';
|
||||
|
||||
@@ -47,6 +47,7 @@ export default [
|
||||
['data_viewer_refresh_result_set', 'Refresh result set'],
|
||||
['data_viewer_total_count_tooltip', 'Get total count'],
|
||||
['data_viewer_total_count_failed', 'Failed to get total count'],
|
||||
['data_viewer_model_not_loaded', 'Table model is not loaded'],
|
||||
['settings_data_editor', 'Data Editor'],
|
||||
['settings_data_editor_disable_edit_name', 'Disable Edit'],
|
||||
['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer'],
|
||||
|
||||
@@ -40,6 +40,7 @@ export default [
|
||||
['data_viewer_refresh_result_set', 'Refresh result set'],
|
||||
['data_viewer_total_count_tooltip', 'Get total count'],
|
||||
['data_viewer_total_count_failed', 'Failed to get total count'],
|
||||
['data_viewer_model_not_loaded', 'Table model is not loaded'],
|
||||
['settings_data_editor', 'Data Editor'],
|
||||
['settings_data_editor_disable_edit_name', 'Disable Edit'],
|
||||
['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer'],
|
||||
|
||||
@@ -41,6 +41,7 @@ export default [
|
||||
['data_viewer_refresh_result_set', 'Обновить резалт сет'],
|
||||
['data_viewer_total_count_tooltip', 'Получить количество записей'],
|
||||
['data_viewer_total_count_failed', 'Не удалось получить количество записей'],
|
||||
['data_viewer_model_not_loaded', 'Не удалось загрузить модель таблицы'],
|
||||
['settings_data_editor', 'Редактор данных'],
|
||||
['settings_data_editor_disable_edit_name', 'Отключить редактирование'],
|
||||
['settings_data_editor_disable_edit_description', 'Отключить редактирование данных'],
|
||||
|
||||
@@ -47,6 +47,7 @@ export default [
|
||||
['data_viewer_refresh_result_set', 'Refresh result set'],
|
||||
['data_viewer_total_count_failed', 'Failed to get total count'],
|
||||
['data_viewer_total_count_tooltip', 'Get total count'],
|
||||
['data_viewer_model_not_loaded', 'Table model is not loaded'],
|
||||
['settings_data_editor', 'Data Editor'],
|
||||
['settings_data_editor_disable_edit_name', 'Disable Edit'],
|
||||
['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer'],
|
||||
|
||||
@@ -280,8 +280,8 @@ export class QueryDataSource<TOptions extends IDataQueryOptions = IDataQueryOpti
|
||||
contextId: executionContextInfo.id,
|
||||
dataFormat: result.dataFormat!,
|
||||
updateRowCount: result.updateRowCount || 0,
|
||||
loadedFully: (result.resultSet?.rows?.length || 0) < limit,
|
||||
count: result.resultSet?.rows?.length || 0,
|
||||
loadedFully: (result.resultSet?.rowsWithMetaData?.length || 0) < limit,
|
||||
count: result.resultSet?.rowsWithMetaData?.length || 0,
|
||||
totalCount: null,
|
||||
// allays returns false
|
||||
// || !result.resultSet?.hasMoreData,
|
||||
|
||||
Reference in New Issue
Block a user