From be16e37f71fd27d06b8cfb1a95307051543e06c1 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Fri, 26 Jan 2024 15:14:56 +0400 Subject: [PATCH 01/37] CB-4457. Add api for read subcollections firestore --- .../schema/service.sql.graphqls | 9 ++++ .../service/sql/DBWServiceSQL.java | 9 ++++ .../service/sql/WebSQLProcessor.java | 45 +++++++++++++++++++ .../service/sql/WebSQLQueryDataReceiver.java | 1 + .../service/sql/WebSQLQueryResultSet.java | 11 +++++ .../service/sql/WebServiceBindingSQL.java | 7 +++ .../service/sql/impl/WebServiceSQL.java | 19 ++++++-- 7 files changed, 98 insertions(+), 3 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index e4db4689e6..69a4f32c61 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -112,6 +112,7 @@ type SQLResultSet { hasMoreData: Boolean! # can't update data or load LOB file if hasRowIdentifier = false hasRowIdentifier: Boolean! + hasChildrenCollection: Boolean! } type SQLQueryResults { @@ -386,4 +387,12 @@ extend type Mutation { ): AsyncTaskInfo! asyncSqlRowDataCountResult(taskId: ID!): Int! + + getChildrenCollection( + projectId: ID, + connectionId: ID, + contextId: ID!, + resultsId: ID!, + row: SQLResultRow! + ): Object } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java index 3dcb4b5f64..915c11a0d8 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java @@ -172,4 +172,13 @@ String generateGroupByQuery(@NotNull WebSQLContextInfo contextInfo, @Nullable @WebAction Long getRowDataCountResult(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException; + + @Nullable + @WebAction + List getChildrenCollection( + @NotNull WebSQLContextInfo contextInfo, + @NotNull WebSession webSession, + @NotNull String resultsId, + @NotNull WebSQLResultsRow value + ) throws DBException; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index be9715377c..15da2623cc 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -897,6 +897,51 @@ public T getDataContainerByNodePath(DBRProgressMonitor monitor, @NotNull Str return type.cast(object); } + public List transformChildSubCollectionValue( + @NotNull WebSession webSession, + @NotNull WebSQLResultsInfo resultsInfo, + @NotNull WebSQLResultsRow value + ) throws DBException { + DBCExecutionContext executionContext = getExecutionContext(resultsInfo.getDataContainer()); + DBSDataContainer dataContainer = resultsInfo.getDataContainer(); + DBDAttributeBinding[] keyAttributes = resultsInfo.getDefaultRowIdentifier().getAttributes().toArray(new DBDAttributeBinding[0]); + Object[] rowValues = new Object[keyAttributes.length]; + List documents1 = new ArrayList<>(); + try (DBCSession session = executionContext.openSession(webSession.getProgressMonitor(), DBCExecutionPurpose.UTIL, "Convert value")) { + for (int i = 0; i < keyAttributes.length; i++) { + DBDAttributeBinding keyAttribute = keyAttributes[i]; + boolean isDocumentValue = keyAttributes.length == 1 && keyAttribute.getDataKind() == DBPDataKind.DOCUMENT; + if (isDocumentValue) { + rowValues[i] = + makeDocumentInputValue(session, (DBSDocumentLocator) dataContainer, resultsInfo, value); + } else { + Object inputCellValue = value.getData(); + + documents1.add(keyAttribute.getValueHandler().getValueFromObject( + session, + keyAttribute, + convertInputCellValue(session, keyAttribute, + inputCellValue, false), + false, + true)); + } + } + if (dataContainer instanceof DBCDocumentHierarchical dbcDocumentHierarchical) { + List documents = new ArrayList<>(); + + List childrenList = dbcDocumentHierarchical.listChildrenEntities(webSession.getProgressMonitor()); + childrenList.forEach(child -> documents.add(new WebSQLDatabaseDocument(webSession, (DBDDocument) child))); + + return documents; + } else { + throw new DBException("Attribute value is not a subcollection"); + } + } catch (Exception e) { + throw new DBException("Error transforming child subcollection value", e); + } + } + + private void fillQueryResults( @NotNull WebSQLContextInfo contextInfo, diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index a75a5cbedf..6199a6d67f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -131,6 +131,7 @@ public void fetchEnd(DBCSession session, DBCResultSet resultSet) throws DBCExcep webResultSet.setColumns(bindings); webResultSet.setRows(rows.toArray(new Object[0][])); + webResultSet.setHasChildrenCollection(resultSet instanceof DBDSubCollectionResultSet); WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, bindings); webResultSet.setResultsInfo(resultsInfo); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java index 74576c2da3..5efd119967 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java @@ -34,6 +34,8 @@ public class WebSQLQueryResultSet { private boolean singleEntity = true; private boolean hasRowIdentifier; + private boolean hasChildrenCollection; + public WebSQLQueryResultSet() { } @@ -102,4 +104,13 @@ public boolean isHasRowIdentifier() { public void setHasRowIdentifier(boolean hasRowIdentifier) { this.hasRowIdentifier = hasRowIdentifier; } + + @Property + public boolean isHasChildrenCollection() { + return hasChildrenCollection; + } + + public void setHasChildrenCollection(boolean hasSuCollection) { + this.hasChildrenCollection = hasSuCollection; + } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java index cc266b8265..d9eddbadf2 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java @@ -203,6 +203,13 @@ public void bindWiring(DBWBindingContext model) throws DBWebException { getSQLContext(env), env.getArgument("resultsId") )) + .dataFetcher("getChildrenCollection", env -> + getService(env).getChildrenCollection( + getSQLContext(env), + getWebSession(env), + env.getArgument("resultsId"), + new WebSQLResultsRow(env.getArgument("row"))) + ) .dataFetcher("asyncSqlRowDataCountResult", env -> getService(env).getRowDataCountResult( getWebSession(env), diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index dc4aef0309..f04a92780c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -33,9 +33,7 @@ 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; @@ -583,4 +581,19 @@ public Long getRowDataCountResult(@NotNull WebSession webSession, @NotNull Strin return null; } + @Nullable + @Override + public List getChildrenCollection( + @NotNull WebSQLContextInfo contextInfo, + @NotNull WebSession webSession, + @NotNull String resultsId, + @NotNull WebSQLResultsRow value + ) throws DBException { + return contextInfo.getProcessor().transformChildSubCollectionValue( + webSession, + contextInfo.getResults(resultsId), + value + ); + } + } From dc72807b14c6f94cfb3f452c6b601f1146e04670 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Sun, 28 Jan 2024 22:58:34 +0400 Subject: [PATCH 02/37] CB-4457. Move firestore to ee module --- .../io.cloudbeaver.server/schema/service.sql.graphqls | 7 ------- .../src/io/cloudbeaver/service/sql/DBWServiceSQL.java | 9 --------- .../io/cloudbeaver/service/sql/WebServiceBindingSQL.java | 7 ------- 3 files changed, 23 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 69a4f32c61..7e3d1ce90f 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -388,11 +388,4 @@ extend type Mutation { asyncSqlRowDataCountResult(taskId: ID!): Int! - getChildrenCollection( - projectId: ID, - connectionId: ID, - contextId: ID!, - resultsId: ID!, - row: SQLResultRow! - ): Object } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java index 915c11a0d8..3dcb4b5f64 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java @@ -172,13 +172,4 @@ String generateGroupByQuery(@NotNull WebSQLContextInfo contextInfo, @Nullable @WebAction Long getRowDataCountResult(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException; - - @Nullable - @WebAction - List getChildrenCollection( - @NotNull WebSQLContextInfo contextInfo, - @NotNull WebSession webSession, - @NotNull String resultsId, - @NotNull WebSQLResultsRow value - ) throws DBException; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java index d9eddbadf2..cc266b8265 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java @@ -203,13 +203,6 @@ public void bindWiring(DBWBindingContext model) throws DBWebException { getSQLContext(env), env.getArgument("resultsId") )) - .dataFetcher("getChildrenCollection", env -> - getService(env).getChildrenCollection( - getSQLContext(env), - getWebSession(env), - env.getArgument("resultsId"), - new WebSQLResultsRow(env.getArgument("row"))) - ) .dataFetcher("asyncSqlRowDataCountResult", env -> getService(env).getRowDataCountResult( getWebSession(env), From fa0f75c69a596c8b552e066f22c643aa6a0d129e Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Sun, 28 Jan 2024 23:44:02 +0400 Subject: [PATCH 03/37] CB-4457. Move firestore to ee module --- .../service/sql/impl/WebServiceSQL.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index f04a92780c..98085edd07 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -581,19 +581,4 @@ public Long getRowDataCountResult(@NotNull WebSession webSession, @NotNull Strin return null; } - @Nullable - @Override - public List getChildrenCollection( - @NotNull WebSQLContextInfo contextInfo, - @NotNull WebSession webSession, - @NotNull String resultsId, - @NotNull WebSQLResultsRow value - ) throws DBException { - return contextInfo.getProcessor().transformChildSubCollectionValue( - webSession, - contextInfo.getResults(resultsId), - value - ); - } - } From f94eef453d4e60d4682c5ceb2c6fac86346ba940 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Mon, 29 Jan 2024 16:54:23 +0400 Subject: [PATCH 04/37] CB-4457. Added annotations for firestore --- .../io/cloudbeaver/service/sql/WebSQLProcessor.java | 11 +++++++++++ .../io/cloudbeaver/service/sql/WebSQLResultsRow.java | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index 15da2623cc..f785b44497 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -563,10 +563,16 @@ private DBSDataManipulator generateUpdateResultsDataBatch( Map 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 metaData = row.getMetaData().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); + if (finalRow.length == 0 || CommonUtils.isEmpty(updateValues)) { continue; } DBDAttributeBinding[] updateAttributes = new DBDAttributeBinding[updateValues.size()]; + DBDAttributeBinding[] metaDataAttributes = new DBDAttributeBinding[metaData.size()]; // Final row is what we return back int index = 0; @@ -575,6 +581,11 @@ private DBSDataManipulator generateUpdateResultsDataBatch( updateAttributes[index++] = allAttributes[attrIndex]; } + for (String indexStr : metaData.keySet()) { + int attrIndex = CommonUtils.toInt(indexStr, -1); + metaDataAttributes[index++] = allAttributes[attrIndex]; + } + Object[] rowValues = new Object[updateAttributes.length + keyAttributes.length]; // put key values first in case of updating them for (int i = 0; i < keyAttributes.length; i++) { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java index 3b01391db1..69fdfff376 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java @@ -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 updateValues; + @Nullable + private Map metaData; + public WebSQLResultsRow() { } public WebSQLResultsRow(Map map) { data = JSONUtils.getObjectList(map, "data").toArray(); updateValues = JSONUtils.getObject(map, "updateValues"); + updateValues = JSONUtils.getObjectOrNull(map, "metaData"); } public Object[] getData() { @@ -43,4 +48,9 @@ public Object[] getData() { public Map getUpdateValues() { return updateValues; } + + @Nullable + public Map getMetaData() { + return metaData; + } } From 171e04f8ab99dc507ac59fe471f009136cabe8c9 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Mon, 29 Jan 2024 19:22:54 +0400 Subject: [PATCH 05/37] CB-4457. Added metaData --- .../io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java | 4 ++++ .../src/io/cloudbeaver/service/sql/WebSQLResultsRow.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index 6199a6d67f..cdf1012d6c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; class WebSQLQueryDataReceiver implements DBDDataReceiver { private static final Log log = Log.getLog(WebSQLQueryDataReceiver.class); @@ -43,6 +44,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver { private DBDAttributeBinding[] bindings; private List rows = new ArrayList<>(); + private List metData = new ArrayList<>(); private final Number rowLimit; WebSQLQueryDataReceiver(WebSQLContextInfo contextInfo, DBSDataContainer dataContainer, WebDataFormat dataFormat) { @@ -81,6 +83,8 @@ public void fetchRow(DBCSession session, DBCResultSet resultSet) throws DBCExcep binding.getMetaAttribute(), i); row[i] = cellValue; + + metData.add(Map.of()); } catch (Throwable e) { row[i] = new DBDValueError(e); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java index 69fdfff376..38a7c1acea 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java @@ -38,7 +38,7 @@ public WebSQLResultsRow() { public WebSQLResultsRow(Map map) { data = JSONUtils.getObjectList(map, "data").toArray(); updateValues = JSONUtils.getObject(map, "updateValues"); - updateValues = JSONUtils.getObjectOrNull(map, "metaData"); + metaData = JSONUtils.getObjectOrNull(map, "metaData"); } public Object[] getData() { From 2fcea143800a45e138a71fac8a578d97a50cc747 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Mon, 29 Jan 2024 20:01:05 +0400 Subject: [PATCH 06/37] CB-4457. Fixed build --- .../src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index cdf1012d6c..9feab294df 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -84,7 +84,7 @@ public void fetchRow(DBCSession session, DBCResultSet resultSet) throws DBCExcep i); row[i] = cellValue; - metData.add(Map.of()); +// metData.add(Map.of()); } catch (Throwable e) { row[i] = new DBDValueError(e); } From 55acd5211d67057a917c38ff0b4f6ebe799ec79e Mon Sep 17 00:00:00 2001 From: naumov Date: Mon, 29 Jan 2024 22:11:50 +0100 Subject: [PATCH 07/37] CB-4457 add hasChildrenCollection flag --- .../queries/grid/getSqlExecuteTaskResults.gql | 83 +++++++++---------- .../queries/grid/updateResultsDataBatch.gql | 59 ++++++------- 2 files changed, 70 insertions(+), 72 deletions(-) diff --git a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql index ff32fdc4d1..f658165edf 100644 --- a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql +++ b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql @@ -1,46 +1,43 @@ -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 + } } + rows + singleEntity + hasMoreData + hasRowIdentifier + hasChildrenCollection + } } + } } diff --git a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql index 296a1fa30b..ebb1e2c08a 100644 --- a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql +++ b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql @@ -1,33 +1,34 @@ 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 + rows + singleEntity + hasMoreData + hasRowIdentifier + hasChildrenCollection + } } -} \ No newline at end of file + } +} From 8695dc4948a501ba33fc09d926fc4596dd2fbe09 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Tue, 30 Jan 2024 16:48:02 +0400 Subject: [PATCH 08/37] CB-4457. Add new resultsRow --- .../schema/service.sql.graphqls | 8 +++- .../service/sql/WebSQLProcessor.java | 25 +++++------ .../service/sql/WebSQLQueryDataReceiver.java | 41 ++++++++++++------- .../service/sql/WebSQLQueryResultSet.java | 15 ++++++- .../service/sql/WebSQLQueryResultSetRow.java | 33 +++++++++++++++ .../service/sql/WebSQLQueryResults.java | 14 ++++--- 6 files changed, 100 insertions(+), 36 deletions(-) create mode 100644 server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 7e3d1ce90f..07ed1e0e7d 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -93,6 +93,11 @@ type SQLResultColumn { supportedOperations: [DataTypeLogicalOperation!]! } +type SQLResultRowMetaData { + first: [Object] + second: [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 diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index f785b44497..720546d661 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -51,6 +51,7 @@ import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; +import org.jkiss.utils.Pair; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -331,7 +332,7 @@ public WebSQLExecuteInfo updateResultsDataBatch( { // we don't need to add same row several times // (it can be when we update the row from RS with several tables) - Set newResultSetRows = new LinkedHashSet<>(); + Set newResultSetRows = new LinkedHashSet<>(); KeyDataReceiver keyReceiver = new KeyDataReceiver(contextInfo.getResults(resultsId)); WebSQLResultsInfo resultsInfo = contextInfo.getResults(resultsId); @@ -372,7 +373,7 @@ public WebSQLExecuteInfo updateResultsDataBatch( 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 +400,7 @@ public WebSQLExecuteInfo updateResultsDataBatch( 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 +411,7 @@ public WebSQLExecuteInfo updateResultsDataBatch( private void getUpdatedRowsInfo( @NotNull WebSQLResultsInfo resultsInfo, - @NotNull Set newResultSetRows, + @NotNull Set newResultSetRows, @Nullable WebDataFormat dataFormat, @NotNull DBRProgressMonitor monitor) throws DBCException { @@ -420,8 +421,8 @@ private void getUpdatedRowsInfo( "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 +439,7 @@ private void getUpdatedRowsInfo( 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 +456,7 @@ private void getUpdatedRowsInfo( } 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 +472,14 @@ private void getUpdatedRowsInfo( 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); } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index 9feab294df..dbbca356f2 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -25,14 +25,16 @@ 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 org.jkiss.utils.Pair; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +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); @@ -43,8 +45,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver { private final WebSQLQueryResultSet webResultSet = new WebSQLQueryResultSet(); private DBDAttributeBinding[] bindings; - private List rows = new ArrayList<>(); - private List metData = new ArrayList<>(); + private List rows = new ArrayList<>(); //new Class WebSQLQueryResultSetRow private final Number rowLimit; WebSQLQueryDataReceiver(WebSQLContextInfo contextInfo, DBSDataContainer dataContainer, WebDataFormat dataFormat) { @@ -72,6 +73,7 @@ public void fetchStart(DBCSession session, DBCResultSet dbResult, long offset, l @Override public void fetchRow(DBCSession session, DBCResultSet resultSet) throws DBCException { + Map metaDataMap = null; Object[] row = new Object[bindings.length]; for (int i = 0; i < bindings.length; i++) { @@ -83,14 +85,23 @@ public void fetchRow(DBCSession session, DBCResultSet resultSet) throws DBCExcep binding.getMetaAttribute(), i); row[i] = cellValue; + Method[] methods = Objects.requireNonNull(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); + } + } -// metData.add(Map.of()); } 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( @@ -105,7 +116,7 @@ public void fetchEnd(DBCSession session, DBCResultSet resultSet) throws DBCExcep 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); } @@ -126,15 +137,15 @@ public void fetchEnd(DBCSession session, DBCResultSet resultSet) throws DBCExcep } // 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); WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, bindings); @@ -162,14 +173,14 @@ private void convertComplexValuesToRelationalView(DBCSession session) { // 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 newRows = new ArrayList<>(); - for (Object[] row : rows) { + List 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, @@ -183,7 +194,7 @@ private void convertComplexValuesToRelationalView(DBCSession session) { newRow[i] = new DBDValueError(e); } } - newRows.add(newRow); + newRows.add(new WebSQLQueryResultSetRow(newRow, row.getMetaData())); } this.bindings = leafAttributes; this.rows = newRows; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java index 5efd119967..603915c840 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java @@ -19,6 +19,11 @@ 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,7 +33,7 @@ public class WebSQLQueryResultSet { private static final Log log = Log.getLog(WebSQLQueryResultSet.class); private WebSQLQueryResultColumn[] columns; - private Object[][] rows; + private List rows; private boolean hasMoreData; private WebSQLResultsInfo resultsInfo; private boolean singleEntity = true; @@ -62,11 +67,17 @@ public void setColumns(DBDAttributeBinding[] bindings) { } @Property + @Deprecated public Object[][] getRows() { + return rows.stream().map(WebSQLQueryResultSetRow::getData).toArray(x -> new Object[x][1]); + } + + @Property + public List getRowsWithMetaData() { return rows; } - public void setRows(Object[][] rows) { + public void setRows(List rows) { this.rows = rows; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java new file mode 100644 index 0000000000..34b8d46f9a --- /dev/null +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java @@ -0,0 +1,33 @@ +package io.cloudbeaver.service.sql; + +import org.jkiss.utils.Pair; + +import java.util.Map; + +public class WebSQLQueryResultSetRow { + + private Object[] data; + + private Map metaData; + + public WebSQLQueryResultSetRow(Object[] data, Map metaData) { + this.data = data; + this.metaData = metaData; + } + + public Object[] getData() { + return data; + } + + public Map getMetaData() { + return metaData; + } + + public void setData(Object[] data) { + this.data = data; + } + + public void setMetaData(Map metaData) { + this.metaData = metaData; + } +} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResults.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResults.java index 36940912e9..8dd7690a51 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResults.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResults.java @@ -25,9 +25,11 @@ 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 List getDocuments() throws DBCException { } List 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()); } } From 3ec850ebda6f2fc2af075947d2097002ef2e9e0a Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Tue, 30 Jan 2024 21:02:35 +0400 Subject: [PATCH 09/37] CB-4457. Renamed SQLResultRowMetaData parameters --- .../bundles/io.cloudbeaver.server/schema/service.sql.graphqls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 07ed1e0e7d..b949d5b246 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -94,8 +94,8 @@ type SQLResultColumn { } type SQLResultRowMetaData { - first: [Object] - second: [Object!] + data: [Object] + metaData: [Object!] } type DatabaseDocument { From b43ac2e41dacc29663265d0b58724898874c6e2a Mon Sep 17 00:00:00 2001 From: naumov Date: Tue, 30 Jan 2024 18:50:23 +0100 Subject: [PATCH 10/37] CB-4457 add rows with metadata to schema --- .../src/queries/grid/getSqlExecuteTaskResults.gql | 4 ++++ .../src/queries/grid/updateResultsDataBatch.gql | 4 ++++ .../Actions/ResultSet/ResultSetDataAction.ts | 13 +++++++++++++ 3 files changed, 21 insertions(+) diff --git a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql index f658165edf..3dcb99b142 100644 --- a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql +++ b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql @@ -33,6 +33,10 @@ mutation getSqlExecuteTaskResults($taskId: ID!) { } } rows + rowsWithMetaData { + data + metaData + } singleEntity hasMoreData hasRowIdentifier diff --git a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql index ebb1e2c08a..286084c78f 100644 --- a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql +++ b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql @@ -24,6 +24,10 @@ mutation updateResultsDataBatch( resultSet { id rows + rowsWithMetaData { + data + metaData + } singleEntity hasMoreData hasRowIdentifier diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts index 62498fead3..871936a4fa 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts @@ -27,6 +27,10 @@ export class ResultSetDataAction extends DatabaseDataResultAction= this.rowsWithMetadata.length) { + return undefined; + } + + return this.rowsWithMetadata[row.index].metaData; + } + getCellValue(cell: IResultSetElementKey): IResultSetValue | undefined { if (cell.row === undefined || cell.column === undefined || cell.row.index >= this.rows.length || cell.column.index >= this.columns.length) { return undefined; From c1c39065004880bea5705c752c33a89afebc9e8f Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Tue, 30 Jan 2024 22:32:11 +0400 Subject: [PATCH 11/37] CB-4457. Fix gql --- .../io.cloudbeaver.server/schema/service.sql.graphqls | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index b949d5b246..0b5d769ef4 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -95,7 +95,7 @@ type SQLResultColumn { type SQLResultRowMetaData { data: [Object] - metaData: [Object!] + metaData: Object } type DatabaseDocument { @@ -153,6 +153,11 @@ input SQLResultRow { updateValues: Object } +input SQLResultRowMetaDataInput { + data: [Object] + metaData: [Object!] +} + type DataTypeLogicalOperation { id: ID! expression: String! From 2332f9886c03ac00eea19693eaa7a64f8f43c29d Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Wed, 31 Jan 2024 14:45:01 +0400 Subject: [PATCH 12/37] CB-4457. Added logic to get Firestore subcollection --- .../service/sql/WebSQLDatabaseDocument.java | 2 +- .../service/sql/WebSQLProcessor.java | 43 +++---------------- .../service/sql/WebSQLResultsRow.java | 2 +- 3 files changed, 9 insertions(+), 38 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java index 32603be86b..7b6327b91f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java @@ -37,7 +37,7 @@ public class WebSQLDatabaseDocument { @Nullable private DBDDocument document; - WebSQLDatabaseDocument(@NotNull WebSession webSession, @Nullable DBDDocument document) { + public WebSQLDatabaseDocument(@NotNull WebSession webSession, @Nullable DBDDocument document) { this.webSession = webSession; this.document = document; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index 720546d661..845ac378e3 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -28,6 +28,7 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.DBCHierarchicalDocumentProvider; import org.jkiss.dbeaver.model.DBPDataKind; import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.DBUtils; @@ -51,7 +52,6 @@ import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; -import org.jkiss.utils.Pair; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -909,48 +909,19 @@ public T getDataContainerByNodePath(DBRProgressMonitor monitor, @NotNull Str return type.cast(object); } - public List transformChildSubCollectionValue( - @NotNull WebSession webSession, + public List transformChildSubCollectionValue( @NotNull WebSQLResultsInfo resultsInfo, @NotNull WebSQLResultsRow value ) throws DBException { - DBCExecutionContext executionContext = getExecutionContext(resultsInfo.getDataContainer()); DBSDataContainer dataContainer = resultsInfo.getDataContainer(); - DBDAttributeBinding[] keyAttributes = resultsInfo.getDefaultRowIdentifier().getAttributes().toArray(new DBDAttributeBinding[0]); - Object[] rowValues = new Object[keyAttributes.length]; - List documents1 = new ArrayList<>(); - try (DBCSession session = executionContext.openSession(webSession.getProgressMonitor(), DBCExecutionPurpose.UTIL, "Convert value")) { - for (int i = 0; i < keyAttributes.length; i++) { - DBDAttributeBinding keyAttribute = keyAttributes[i]; - boolean isDocumentValue = keyAttributes.length == 1 && keyAttribute.getDataKind() == DBPDataKind.DOCUMENT; - if (isDocumentValue) { - rowValues[i] = - makeDocumentInputValue(session, (DBSDocumentLocator) dataContainer, resultsInfo, value); - } else { - Object inputCellValue = value.getData(); - - documents1.add(keyAttribute.getValueHandler().getValueFromObject( - session, - keyAttribute, - convertInputCellValue(session, keyAttribute, - inputCellValue, false), - false, - true)); - } - } - if (dataContainer instanceof DBCDocumentHierarchical dbcDocumentHierarchical) { - List documents = new ArrayList<>(); - - List childrenList = dbcDocumentHierarchical.listChildrenEntities(webSession.getProgressMonitor()); - childrenList.forEach(child -> documents.add(new WebSQLDatabaseDocument(webSession, (DBDDocument) child))); - - return documents; + if (dataContainer.getDataSource() instanceof DBCHierarchicalDocumentProvider documentProvider) { + return (List) documentProvider + .listChildrenEntities((String) Objects.requireNonNull(value.getMetaData()).get("path"), + getWebSession().getProgressMonitor(), + true); } else { throw new DBException("Attribute value is not a subcollection"); } - } catch (Exception e) { - throw new DBException("Error transforming child subcollection value", e); - } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java index 38a7c1acea..4ea9d99608 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java @@ -38,7 +38,7 @@ public WebSQLResultsRow() { public WebSQLResultsRow(Map map) { data = JSONUtils.getObjectList(map, "data").toArray(); updateValues = JSONUtils.getObject(map, "updateValues"); - metaData = JSONUtils.getObjectOrNull(map, "metaData"); + metaData = JSONUtils.getObjectList(map, "metaData").get(0); } public Object[] getData() { From 0186f6f248ecb05f84812678a5a98b9a7ed17d17 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Wed, 31 Jan 2024 15:26:58 +0400 Subject: [PATCH 13/37] CB-4457. Refactor result, rename gql, added new type to return gql --- .../bundles/io.cloudbeaver.server/schema/service.sql.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 0b5d769ef4..d45cf2a1a4 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -155,7 +155,7 @@ input SQLResultRow { input SQLResultRowMetaDataInput { data: [Object] - metaData: [Object!] + metaData: Object! } type DataTypeLogicalOperation { From f69b31bf075c312d39ec889312f5588b8bb2a933 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Wed, 31 Jan 2024 17:48:17 +0400 Subject: [PATCH 14/37] CB-4457. Revert list to map --- .../src/io/cloudbeaver/service/sql/WebSQLResultsRow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java index 4ea9d99608..d651f44179 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultsRow.java @@ -38,7 +38,7 @@ public WebSQLResultsRow() { public WebSQLResultsRow(Map map) { data = JSONUtils.getObjectList(map, "data").toArray(); updateValues = JSONUtils.getObject(map, "updateValues"); - metaData = JSONUtils.getObjectList(map, "metaData").get(0); + metaData = JSONUtils.getObject(map, "metaData"); } public Object[] getData() { From 169f4c936c0a6236eed0872aa306185bf6a4fb4b Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Thu, 1 Feb 2024 16:35:51 +0400 Subject: [PATCH 15/37] CB-4457. Get Subcollections info --- .../schema/service.sql.graphqls | 11 ++++ .../service/sql/DBWServiceSQL.java | 8 +++ .../service/sql/WebSQLProcessor.java | 15 ++++++ .../service/sql/WebServiceBindingSQL.java | 8 +++ .../service/sql/impl/WebServiceSQL.java | 50 +++++++++++++++++++ 5 files changed, 92 insertions(+) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index d45cf2a1a4..0dcae22bdf 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -316,6 +316,17 @@ extend type Mutation { dataFormat: ResultDataFormat ): AsyncTaskInfo! + # Read data from subcollection + asyncReadDataFromChildEntity( + projectId: ID, + connectionId: ID!, + contextId: ID!, + path: ID, + resultId: ID, + filter: SQLDataFilter, + dataFormat: ResultDataFormat + ): AsyncTaskInfo! + # Close results (free resources) sqlResultClose(projectId: ID, connectionId: ID!, contextId: ID!, resultId: ID!): Boolean! diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java index 3dcb4b5f64..4fa93f8631 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java @@ -106,6 +106,14 @@ WebAsyncTaskInfo asyncReadDataFromContainer( @Nullable WebSQLDataFilter filter, @Nullable WebDataFormat dataFormat) throws DBWebException; + @WebAction + WebAsyncTaskInfo asyncReadDataFromChildEntity( + @NotNull WebSQLContextInfo contextInfo, + @NotNull String path, + @Nullable String resultId, + @Nullable WebSQLDataFilter filter, + @Nullable WebDataFormat dataFormat) throws DBWebException; + @WebAction Boolean closeResult(@NotNull WebSQLContextInfo sqlContext, @NotNull String resultId) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index 845ac378e3..81859e6810 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -924,6 +924,21 @@ public List transformChildSubCollectionValue( } } + public DBSEntity getChildEntity( + @NotNull WebSQLResultsInfo resultsInfo, + @NotNull WebSQLResultsRow value + ) throws DBException { + DBSDataContainer dataContainer = resultsInfo.getDataContainer(); + if (dataContainer.getDataSource() instanceof DBCHierarchicalDocumentProvider documentProvider) { + return documentProvider + .getChildrenEntityInstance((String) Objects.requireNonNull(value.getMetaData()).get("path"), + getWebSession().getProgressMonitor(), + true, true); + } else { + throw new DBException("Attribute value is not a subcollection"); + } + } + private void fillQueryResults( diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java index cc266b8265..853de45b8b 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java @@ -183,6 +183,14 @@ public void bindWiring(DBWBindingContext model) throws DBWebException { getDataFilter(env), getDataFormat(env) )) + .dataFetcher("asyncReadDataFromChildEntity", env -> + getService(env).asyncReadDataFromChildEntity( + getSQLContext(env), + env.getArgument("path"), + env.getArgument("resultId"), + getDataFilter(env), + getDataFormat(env) + )) .dataFetcher("asyncSqlExecuteResults", env -> getService(env).asyncGetQueryResults( getWebSession(env), env.getArgument("taskId") diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index 98085edd07..6f52a93279 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -29,6 +29,7 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.DBCHierarchicalDocumentProvider; import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.DBPDataSourceContainer; import org.jkiss.dbeaver.model.DBUtils; @@ -48,6 +49,7 @@ 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; @@ -456,6 +458,54 @@ public void run(DBRProgressMonitor monitor) throws InvocationTargetException, In return contextInfo.getProcessor().getWebSession().createAndRunAsyncTask("Read data from container " + nodePath, runnable); } + @Override + public WebAsyncTaskInfo asyncReadDataFromChildEntity( + @NotNull WebSQLContextInfo contextInfo, + @Nullable String path, + @Nullable String resultId, + @Nullable WebSQLDataFilter filter, + @Nullable WebDataFormat dataFormat) throws DBWebException { + WebAsyncTaskProcessor runnable = new WebAsyncTaskProcessor<>() { + @Override + public void run(DBRProgressMonitor monitor) throws InvocationTargetException { + try { + monitor.beginTask("Read data", 1); + monitor.subTask("Extra data from " + path); + + DBPDataSource dataSource = contextInfo.getProcessor().getConnection().getDataSource(); + DBSDataContainer dataContainer = null; + + if (dataSource instanceof DBCHierarchicalDocumentProvider provider) { + DBSEntity childrenEntityInstance = + provider.getChildrenEntityInstance(path, monitor, true, true); + if (childrenEntityInstance instanceof DBSDataContainer container) { + dataContainer = container; + } + } + + if (dataContainer == null) { + throw new DBException("Container not found: " + path); + } + + WebSQLExecuteInfo executeResults = contextInfo.getProcessor().readDataFromContainer( + contextInfo, + monitor, + dataContainer, + resultId, + filter != null ? filter : new WebSQLDataFilter(), + dataFormat); + this.result = executeResults.getStatusMessage(); + this.extendedResults = executeResults; + } catch (Throwable e) { + throw new InvocationTargetException(e); + } finally { + monitor.done(); + } + } + }; + return contextInfo.getProcessor().getWebSession().createAndRunAsyncTask("Read data from container " + path, runnable); + } + @Override public WebSQLExecuteInfo asyncGetQueryResults(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException { WebAsyncTaskInfo taskStatus = webSession.asyncTaskStatus(taskId, false); From fcb9e0172a7ed6b232894d8c113ba3dce1e269b1 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Thu, 1 Feb 2024 17:42:20 +0400 Subject: [PATCH 16/37] CB-4457. Refactor code --- .../src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java | 2 +- .../io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java index 7b6327b91f..32603be86b 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLDatabaseDocument.java @@ -37,7 +37,7 @@ public class WebSQLDatabaseDocument { @Nullable private DBDDocument document; - public WebSQLDatabaseDocument(@NotNull WebSession webSession, @Nullable DBDDocument document) { + WebSQLDatabaseDocument(@NotNull WebSession webSession, @Nullable DBDDocument document) { this.webSession = webSession; this.document = document; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index dbbca356f2..373edd8849 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -30,7 +30,6 @@ import org.jkiss.dbeaver.model.struct.DBSDataContainer; import org.jkiss.dbeaver.model.struct.DBSEntity; import org.jkiss.utils.CommonUtils; -import org.jkiss.utils.Pair; import java.lang.reflect.Method; import java.util.*; @@ -45,7 +44,7 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver { private final WebSQLQueryResultSet webResultSet = new WebSQLQueryResultSet(); private DBDAttributeBinding[] bindings; - private List rows = new ArrayList<>(); //new Class WebSQLQueryResultSetRow + private List rows = new ArrayList<>(); private final Number rowLimit; WebSQLQueryDataReceiver(WebSQLContextInfo contextInfo, DBSDataContainer dataContainer, WebDataFormat dataFormat) { From 8e0dc4e3c97470dda798631c170364328da56735 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Fri, 2 Feb 2024 15:15:58 +0400 Subject: [PATCH 17/37] Added sceleton for insert subcollection --- .../schema/service.sql.graphqls | 1 + .../cloudbeaver/service/sql/WebSQLProcessor.java | 15 +++++---------- .../service/sql/WebSQLQueryResultSetRow.java | 2 -- .../service/sql/impl/WebServiceSQL.java | 1 + 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 0dcae22bdf..1ca9f97529 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -151,6 +151,7 @@ type SQLExecuteInfo { input SQLResultRow { data: [ Object ]! updateValues: Object + metaData: Object } input SQLResultRowMetaDataInput { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index 81859e6810..39bddca3f6 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -573,7 +573,6 @@ private DBSDataManipulator generateUpdateResultsDataBatch( continue; } DBDAttributeBinding[] updateAttributes = new DBDAttributeBinding[updateValues.size()]; - DBDAttributeBinding[] metaDataAttributes = new DBDAttributeBinding[metaData.size()]; // Final row is what we return back int index = 0; @@ -582,11 +581,6 @@ private DBSDataManipulator generateUpdateResultsDataBatch( updateAttributes[index++] = allAttributes[attrIndex]; } - for (String indexStr : metaData.keySet()) { - int attrIndex = CommonUtils.toInt(indexStr, -1); - metaDataAttributes[index++] = allAttributes[attrIndex]; - } - Object[] rowValues = new Object[updateAttributes.length + keyAttributes.length]; // put key values first in case of updating them for (int i = 0; i < keyAttributes.length; i++) { @@ -594,7 +588,7 @@ private DBSDataManipulator generateUpdateResultsDataBatch( 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, @@ -705,7 +699,8 @@ public DBDDocument makeDocumentInputValue( DBCSession session, DBSDocumentLocator dataContainer, WebSQLResultsInfo resultsInfo, - WebSQLResultsRow row) throws DBException + WebSQLResultsRow row, + Map metaData) throws DBException { // Document reference DBDDocument document = null; @@ -723,7 +718,7 @@ public DBDDocument makeDocumentInputValue( keyMap.put(attr.getName(), plainValue); } if (document == null) { - document = dataContainer.findDocument(session.getProgressMonitor(), keyMap); + document = dataContainer.findDocument(session.getProgressMonitor(), keyMap, metaData); if (document == null) { throw new DBCException("Error finding document by key " + keyMap); } @@ -838,7 +833,7 @@ private void readCellDataValue( 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()]; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java index 34b8d46f9a..30b4b15966 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSetRow.java @@ -1,7 +1,5 @@ package io.cloudbeaver.service.sql; -import org.jkiss.utils.Pair; - import java.util.Map; public class WebSQLQueryResultSetRow { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index 6f52a93279..ee809279ac 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -33,6 +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.DBCCollectionHierarchical; import org.jkiss.dbeaver.model.data.DBDAttributeBinding; import org.jkiss.dbeaver.model.exec.*; import org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect; From 12d89f895505ae82bc5779201b4a8583308c8d57 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Mon, 5 Feb 2024 16:28:34 +0400 Subject: [PATCH 18/37] CB-4457. Added isSupportsDataFilter flag for subcollection --- .../io.cloudbeaver.server/schema/service.sql.graphqls | 1 + .../service/sql/WebSQLQueryDataReceiver.java | 1 + .../cloudbeaver/service/sql/WebSQLQueryResultSet.java | 10 ++++++++++ 3 files changed, 12 insertions(+) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 0dcae22bdf..00b4f5fcae 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -119,6 +119,7 @@ type SQLResultSet { # can't update data or load LOB file if hasRowIdentifier = false hasRowIdentifier: Boolean! hasChildrenCollection: Boolean! + isSupportsDataFilter: Boolean! } type SQLQueryResults { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index 373edd8849..9d81b015b0 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -146,6 +146,7 @@ public void fetchEnd(DBCSession session, DBCResultSet resultSet) throws DBCExcep webResultSet.setColumns(bindings); webResultSet.setRows(List.of(rows.toArray(new WebSQLQueryResultSetRow[0]))); webResultSet.setHasChildrenCollection(resultSet instanceof DBDSubCollectionResultSet); + webResultSet.setHasChildrenCollection(dataContainer.isFeatureSupported(DBSDataContainer.FEATURE_DATA_FILTER)); WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, bindings); webResultSet.setResultsInfo(resultsInfo); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java index 603915c840..73adabbb4a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultSet.java @@ -40,6 +40,7 @@ public class WebSQLQueryResultSet { private boolean hasRowIdentifier; private boolean hasChildrenCollection; + private boolean isSupportsDataFilter; public WebSQLQueryResultSet() { } @@ -124,4 +125,13 @@ public boolean isHasChildrenCollection() { public void setHasChildrenCollection(boolean hasSuCollection) { this.hasChildrenCollection = hasSuCollection; } + + @Property + public boolean isSupportsDataFilter() { + return isSupportsDataFilter; + } + + public void setSupportsDataFilter(boolean supportsDataFilter) { + isSupportsDataFilter = supportsDataFilter; + } } From b590bfcddc3c8f360d94b8c85713b2d544b10c32 Mon Sep 17 00:00:00 2001 From: naumov Date: Mon, 5 Feb 2024 13:40:40 +0100 Subject: [PATCH 19/37] CB-4457 add locales --- webapp/packages/plugin-data-viewer/src/locales/en.ts | 1 + webapp/packages/plugin-data-viewer/src/locales/it.ts | 1 + webapp/packages/plugin-data-viewer/src/locales/ru.ts | 1 + webapp/packages/plugin-data-viewer/src/locales/zh.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/webapp/packages/plugin-data-viewer/src/locales/en.ts b/webapp/packages/plugin-data-viewer/src/locales/en.ts index 31e16530c0..9c9510355c 100644 --- a/webapp/packages/plugin-data-viewer/src/locales/en.ts +++ b/webapp/packages/plugin-data-viewer/src/locales/en.ts @@ -48,6 +48,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 Edit'], diff --git a/webapp/packages/plugin-data-viewer/src/locales/it.ts b/webapp/packages/plugin-data-viewer/src/locales/it.ts index f365b109fb..b6d86616f2 100644 --- a/webapp/packages/plugin-data-viewer/src/locales/it.ts +++ b/webapp/packages/plugin-data-viewer/src/locales/it.ts @@ -41,6 +41,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 Edit'], diff --git a/webapp/packages/plugin-data-viewer/src/locales/ru.ts b/webapp/packages/plugin-data-viewer/src/locales/ru.ts index 40b067cda2..7f98f05af1 100644 --- a/webapp/packages/plugin-data-viewer/src/locales/ru.ts +++ b/webapp/packages/plugin-data-viewer/src/locales/ru.ts @@ -42,6 +42,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', 'Отключить редактирование'], diff --git a/webapp/packages/plugin-data-viewer/src/locales/zh.ts b/webapp/packages/plugin-data-viewer/src/locales/zh.ts index f00b6e8635..8e0d464c1f 100644 --- a/webapp/packages/plugin-data-viewer/src/locales/zh.ts +++ b/webapp/packages/plugin-data-viewer/src/locales/zh.ts @@ -48,6 +48,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 Edit'], From dda99edf31ef384275e29495504e1239a99e16d8 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Mon, 5 Feb 2024 17:21:51 +0400 Subject: [PATCH 20/37] CB-4457. Added isSupportsDataFilter flag for subcollection --- .../src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index 9d81b015b0..e9fc323fd2 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -146,7 +146,7 @@ public void fetchEnd(DBCSession session, DBCResultSet resultSet) throws DBCExcep webResultSet.setColumns(bindings); webResultSet.setRows(List.of(rows.toArray(new WebSQLQueryResultSetRow[0]))); webResultSet.setHasChildrenCollection(resultSet instanceof DBDSubCollectionResultSet); - webResultSet.setHasChildrenCollection(dataContainer.isFeatureSupported(DBSDataContainer.FEATURE_DATA_FILTER)); + webResultSet.setSupportsDataFilter(dataContainer.isFeatureSupported(DBSDataContainer.FEATURE_DATA_FILTER)); WebSQLResultsInfo resultsInfo = contextInfo.saveResult(dataContainer, bindings); webResultSet.setResultsInfo(resultsInfo); From 2452df1d7c9bce2fd1b81ecbc272296111d702b8 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Mon, 5 Feb 2024 19:11:50 +0400 Subject: [PATCH 21/37] CB-4457. Added update/insert logic for subcollection --- .../src/io/cloudbeaver/service/sql/WebSQLProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index 39bddca3f6..f3f6e78685 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -718,7 +718,7 @@ public DBDDocument makeDocumentInputValue( keyMap.put(attr.getName(), plainValue); } if (document == null) { - document = dataContainer.findDocument(session.getProgressMonitor(), keyMap, metaData); + document = dataContainer.findDocument(session, keyMap, metaData); if (document == null) { throw new DBCException("Error finding document by key " + keyMap); } From 77cc3ce5f6a69089624c334312625dc3c4b2264f Mon Sep 17 00:00:00 2001 From: naumov Date: Tue, 6 Feb 2024 12:47:04 +0100 Subject: [PATCH 22/37] CB-4457 support collection editing --- .../core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql | 1 + .../core-sdk/src/queries/grid/updateResultsDataBatch.gql | 1 + .../DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql index 3dcb99b142..2328ce81f3 100644 --- a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql +++ b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql @@ -40,6 +40,7 @@ mutation getSqlExecuteTaskResults($taskId: ID!) { singleEntity hasMoreData hasRowIdentifier + isSupportsDataFilter hasChildrenCollection } } diff --git a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql index 286084c78f..a3112a2570 100644 --- a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql +++ b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql @@ -31,6 +31,7 @@ mutation updateResultsDataBatch( singleEntity hasMoreData hasRowIdentifier + isSupportsDataFilter hasChildrenCollection } } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts index eca935b74b..93628a4dc1 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts @@ -498,6 +498,7 @@ export class ResultSetEditAction extends DatabaseEditAction Date: Wed, 7 Feb 2024 15:31:11 +0400 Subject: [PATCH 23/37] CB-4457. Refactor after review, moved hierarchical model to ee. --- .../schema/service.sql.graphqls | 11 ---- .../service/sql/DBWServiceSQL.java | 8 --- .../service/sql/WebSQLProcessor.java | 32 ----------- .../service/sql/WebServiceBindingSQL.java | 8 --- .../service/sql/impl/WebServiceSQL.java | 53 ------------------- 5 files changed, 112 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index 83468e1576..b646b3b848 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -318,17 +318,6 @@ extend type Mutation { dataFormat: ResultDataFormat ): AsyncTaskInfo! - # Read data from subcollection - asyncReadDataFromChildEntity( - projectId: ID, - connectionId: ID!, - contextId: ID!, - path: ID, - resultId: ID, - filter: SQLDataFilter, - dataFormat: ResultDataFormat - ): AsyncTaskInfo! - # Close results (free resources) sqlResultClose(projectId: ID, connectionId: ID!, contextId: ID!, resultId: ID!): Boolean! diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java index 4fa93f8631..3dcb4b5f64 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/DBWServiceSQL.java @@ -106,14 +106,6 @@ WebAsyncTaskInfo asyncReadDataFromContainer( @Nullable WebSQLDataFilter filter, @Nullable WebDataFormat dataFormat) throws DBWebException; - @WebAction - WebAsyncTaskInfo asyncReadDataFromChildEntity( - @NotNull WebSQLContextInfo contextInfo, - @NotNull String path, - @Nullable String resultId, - @Nullable WebSQLDataFilter filter, - @Nullable WebDataFormat dataFormat) throws DBWebException; - @WebAction Boolean closeResult(@NotNull WebSQLContextInfo sqlContext, @NotNull String resultId) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index f3f6e78685..275b3efcd4 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -28,7 +28,6 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.model.DBCHierarchicalDocumentProvider; import org.jkiss.dbeaver.model.DBPDataKind; import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.DBUtils; @@ -904,37 +903,6 @@ public T getDataContainerByNodePath(DBRProgressMonitor monitor, @NotNull Str return type.cast(object); } - public List transformChildSubCollectionValue( - @NotNull WebSQLResultsInfo resultsInfo, - @NotNull WebSQLResultsRow value - ) throws DBException { - DBSDataContainer dataContainer = resultsInfo.getDataContainer(); - if (dataContainer.getDataSource() instanceof DBCHierarchicalDocumentProvider documentProvider) { - return (List) documentProvider - .listChildrenEntities((String) Objects.requireNonNull(value.getMetaData()).get("path"), - getWebSession().getProgressMonitor(), - true); - } else { - throw new DBException("Attribute value is not a subcollection"); - } - } - - public DBSEntity getChildEntity( - @NotNull WebSQLResultsInfo resultsInfo, - @NotNull WebSQLResultsRow value - ) throws DBException { - DBSDataContainer dataContainer = resultsInfo.getDataContainer(); - if (dataContainer.getDataSource() instanceof DBCHierarchicalDocumentProvider documentProvider) { - return documentProvider - .getChildrenEntityInstance((String) Objects.requireNonNull(value.getMetaData()).get("path"), - getWebSession().getProgressMonitor(), - true, true); - } else { - throw new DBException("Attribute value is not a subcollection"); - } - } - - private void fillQueryResults( @NotNull WebSQLContextInfo contextInfo, diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java index 853de45b8b..cc266b8265 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java @@ -183,14 +183,6 @@ public void bindWiring(DBWBindingContext model) throws DBWebException { getDataFilter(env), getDataFormat(env) )) - .dataFetcher("asyncReadDataFromChildEntity", env -> - getService(env).asyncReadDataFromChildEntity( - getSQLContext(env), - env.getArgument("path"), - env.getArgument("resultId"), - getDataFilter(env), - getDataFormat(env) - )) .dataFetcher("asyncSqlExecuteResults", env -> getService(env).asyncGetQueryResults( getWebSession(env), env.getArgument("taskId") diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index ee809279ac..8728b647c6 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -29,11 +29,9 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.model.DBCHierarchicalDocumentProvider; import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.DBPDataSourceContainer; import org.jkiss.dbeaver.model.DBUtils; -import org.jkiss.dbeaver.model.data.DBCCollectionHierarchical; import org.jkiss.dbeaver.model.data.DBDAttributeBinding; import org.jkiss.dbeaver.model.exec.*; import org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect; @@ -61,9 +59,6 @@ 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; /** @@ -459,54 +454,6 @@ public void run(DBRProgressMonitor monitor) throws InvocationTargetException, In return contextInfo.getProcessor().getWebSession().createAndRunAsyncTask("Read data from container " + nodePath, runnable); } - @Override - public WebAsyncTaskInfo asyncReadDataFromChildEntity( - @NotNull WebSQLContextInfo contextInfo, - @Nullable String path, - @Nullable String resultId, - @Nullable WebSQLDataFilter filter, - @Nullable WebDataFormat dataFormat) throws DBWebException { - WebAsyncTaskProcessor runnable = new WebAsyncTaskProcessor<>() { - @Override - public void run(DBRProgressMonitor monitor) throws InvocationTargetException { - try { - monitor.beginTask("Read data", 1); - monitor.subTask("Extra data from " + path); - - DBPDataSource dataSource = contextInfo.getProcessor().getConnection().getDataSource(); - DBSDataContainer dataContainer = null; - - if (dataSource instanceof DBCHierarchicalDocumentProvider provider) { - DBSEntity childrenEntityInstance = - provider.getChildrenEntityInstance(path, monitor, true, true); - if (childrenEntityInstance instanceof DBSDataContainer container) { - dataContainer = container; - } - } - - if (dataContainer == null) { - throw new DBException("Container not found: " + path); - } - - WebSQLExecuteInfo executeResults = contextInfo.getProcessor().readDataFromContainer( - contextInfo, - monitor, - dataContainer, - resultId, - filter != null ? filter : new WebSQLDataFilter(), - dataFormat); - this.result = executeResults.getStatusMessage(); - this.extendedResults = executeResults; - } catch (Throwable e) { - throw new InvocationTargetException(e); - } finally { - monitor.done(); - } - } - }; - return contextInfo.getProcessor().getWebSession().createAndRunAsyncTask("Read data from container " + path, runnable); - } - @Override public WebSQLExecuteInfo asyncGetQueryResults(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException { WebAsyncTaskInfo taskStatus = webSession.asyncTaskStatus(taskId, false); From 4a61dffee954052573710eb9be5ffec62971343e Mon Sep 17 00:00:00 2001 From: naumov Date: Wed, 7 Feb 2024 15:19:44 +0100 Subject: [PATCH 24/37] CB-4457 add SerializableKey --- .../src/DataViewerTableService.ts | 4 +- .../Actions/IResultSetCacheAction.ts | 15 ++++ .../ResultSet/ResultSetDataKeysUtils.ts | 4 +- .../Actions/ResultSetCacheAction.ts | 81 +++++++++++++++++++ .../packages/plugin-data-viewer/src/index.ts | 1 + 5 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts create mode 100644 webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts index c449303e73..0d38871517 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerTableService.ts @@ -36,8 +36,8 @@ export class DataViewerTableService { return this.tableViewerStorageService.has(tableId); } - get(modelId: string): IDatabaseDataModel | undefined { - return this.tableViewerStorageService.get(modelId); + get(tableId: string): IDatabaseDataModel | undefined { + return this.tableViewerStorageService.get(tableId); } async removeTableModel(tableId: string): Promise { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts new file mode 100644 index 0000000000..1015e5d8dd --- /dev/null +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts @@ -0,0 +1,15 @@ +/* + * 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 { SerializableKey } from './ResultSet/ResultSetDataKeysUtils'; + +export interface IResultSetCacheAction { + has(key: SerializableKey, scope: string): boolean; + get(key: SerializableKey, scope: string): T | undefined; + set(key: SerializableKey, value: T, scope: string): void; + delete(key: SerializableKey, scope: string): void; +} diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataKeysUtils.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataKeysUtils.ts index 423066d3d6..e4a1642155 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataKeysUtils.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataKeysUtils.ts @@ -7,6 +7,8 @@ */ 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); @@ -14,7 +16,7 @@ export const ResultSetDataKeysUtils = { 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) { diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts new file mode 100644 index 0000000000..27a8e3505f --- /dev/null +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts @@ -0,0 +1,81 @@ +/* + * 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 { IResultSetCacheAction } from './IResultSetCacheAction'; +import { ResultSetDataKeysUtils, type SerializableKey } from './ResultSet/ResultSetDataKeysUtils'; + +@databaseDataAction() +export class ResultSetCacheAction extends DatabaseDataAction implements IResultSetCacheAction { + static dataFormat = [ResultDataFormat.Resultset]; + + private readonly cache: Map>; + + constructor(source: IDatabaseDataSource) { + super(source); + + this.cache = new Map(); + + makeObservable(this, { + cache: observable, + }); + } + + get(key: SerializableKey, scope: string): T | undefined { + const hash = this.getHash(key); + const scopedCache = this.cache.get(scope); + + if (!scopedCache) { + return; + } + + return scopedCache.get(hash); + } + + has(key: SerializableKey, scope: string) { + const hash = this.getHash(key); + const scopedCache = this.cache.get(scope); + + if (!scopedCache) { + return false; + } + + return scopedCache.has(hash); + } + + set(key: SerializableKey, value: T, scope: string) { + const hash = this.getHash(key); + let scopedCache = this.cache.get(scope); + + if (!scopedCache) { + scopedCache = new Map(); + this.cache.set(scope, scopedCache); + } + + scopedCache.set(hash, value); + } + + delete(key: SerializableKey, scope: string) { + const hash = ResultSetDataKeysUtils.serialize(key); + const scopedCache = this.cache.get(scope); + + if (scopedCache) { + scopedCache.delete(hash); + } + } + + private getHash(key: SerializableKey) { + return ResultSetDataKeysUtils.serialize(key); + } +} diff --git a/webapp/packages/plugin-data-viewer/src/index.ts b/webapp/packages/plugin-data-viewer/src/index.ts index cd93e62665..6177aa5739 100644 --- a/webapp/packages/plugin-data-viewer/src/index.ts +++ b/webapp/packages/plugin-data-viewer/src/index.ts @@ -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/ResultSetCacheAction'; export * from './DatabaseDataModel/DatabaseDataAction'; export * from './DatabaseDataModel/DatabaseDataActions'; export * from './DatabaseDataModel/DatabaseDataFormat'; From 3e0ca83ff5e26d97c788b84ee7bc94e6d9ba7472 Mon Sep 17 00:00:00 2001 From: naumov Date: Wed, 7 Feb 2024 16:23:51 +0100 Subject: [PATCH 25/37] CB-4457 keep only new rowsWithMetaData api --- .../src/queries/grid/getSqlExecuteTaskResults.gql | 1 - .../src/queries/grid/updateResultsDataBatch.gql | 1 - .../Actions/ResultSet/ResultSetDataAction.ts | 15 +++++---------- .../Actions/ResultSet/ResultSetViewAction.ts | 4 ++-- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql index 2328ce81f3..4b633ccfc1 100644 --- a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql +++ b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql @@ -32,7 +32,6 @@ mutation getSqlExecuteTaskResults($taskId: ID!) { argumentCount } } - rows rowsWithMetaData { data metaData diff --git a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql index a3112a2570..306137c418 100644 --- a/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql +++ b/webapp/packages/core-sdk/src/queries/grid/updateResultsDataBatch.gql @@ -23,7 +23,6 @@ mutation updateResultsDataBatch( updateRowCount resultSet { id - rows rowsWithMetaData { data metaData diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts index 871936a4fa..b53757d48e 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts @@ -23,11 +23,7 @@ import type { IResultSetValue } from './ResultSetFormatAction'; export class ResultSetDataAction extends DatabaseDataResultAction { static dataFormat = [ResultDataFormat.Resultset]; - get rows(): IResultSetValue[][] { - return this.result.data?.rows || []; - } - - get rowsWithMetadata() { + get rows() { return this.result.data?.rowsWithMetaData || []; } @@ -39,7 +35,6 @@ export class ResultSetDataAction extends DatabaseDataResultAction= this.rowsWithMetadata.length) { + if (row.index >= this.rows.length) { return undefined; } - return this.rowsWithMetadata[row.index].metaData; + return this.rows[row.index].metaData; } getCellValue(cell: IResultSetElementKey): IResultSetValue | undefined { @@ -112,7 +107,7 @@ export class ResultSetDataAction extends DatabaseDataResultAction ({ index: this.data.columns.indexOf(c) })); } - get rows(): IResultSetValue[][] { + get rows() { return this.data.rows; } @@ -137,7 +137,7 @@ export class ResultSetViewAction extends DatabaseDataAction Date: Wed, 7 Feb 2024 20:49:38 +0100 Subject: [PATCH 26/37] CB-4457 review fixes --- .../src/ContainerDataSource.ts | 4 +-- .../Actions/Document/DocumentDataAction.ts | 12 ++++++--- .../Actions/Document/DocumentEditAction.ts | 6 +++-- .../Actions/IDatabaseDataCacheAction.ts | 14 ++++++++++ .../Actions/IResultSetCacheAction.ts | 15 ----------- .../Actions/ResultSet/ResultSetDataAction.ts | 12 ++++----- .../Actions/ResultSet/ResultSetEditAction.ts | 4 +-- .../Actions/ResultSet/ResultSetViewAction.ts | 6 ++--- .../Actions/ResultSetCacheAction.ts | 27 ++++++++++--------- .../plugin-sql-editor/src/QueryDataSource.ts | 4 +-- 10 files changed, 56 insertions(+), 48 deletions(-) create mode 100644 webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataCacheAction.ts delete mode 100644 webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts diff --git a/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts b/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts index 8e96004c75..d8a6618eb0 100644 --- a/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts +++ b/webapp/packages/plugin-data-viewer/src/ContainerDataSource.ts @@ -255,8 +255,8 @@ export class ContainerDataSource extends ResultSetDataSource 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) { @@ -54,8 +54,12 @@ export class DocumentDataAction extends DatabaseDataResultAction { + has(key: TKey, scope: symbol): boolean; + get(key: TKey, scope: symbol): T | undefined; + set(key: TKey, value: T, scope: symbol): void; + delete(key: TKey, scope: symbol): void; +} diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts deleted file mode 100644 index 1015e5d8dd..0000000000 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IResultSetCacheAction.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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 { SerializableKey } from './ResultSet/ResultSetDataKeysUtils'; - -export interface IResultSetCacheAction { - has(key: SerializableKey, scope: string): boolean; - get(key: SerializableKey, scope: string): T | undefined; - set(key: SerializableKey, value: T, scope: string): void; - delete(key: SerializableKey, scope: string): void; -} diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts index b53757d48e..8241f84652 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts @@ -60,9 +60,9 @@ export class ResultSetDataAction extends DatabaseDataResultAction ({ index: this.data.columns.indexOf(c) })); } - get rows() { - return this.data.rows; + get rows(): IResultSetValue[][] { + return this.data.rows.map(row => row.data || []); } get columns(): SqlResultColumn[] { @@ -137,7 +137,7 @@ export class ResultSetViewAction extends DatabaseDataAction implements IResultSetCacheAction { - static dataFormat = [ResultDataFormat.Resultset]; +export class ResultSetCacheAction extends DatabaseDataAction implements IDatabaseDataCacheAction { + static dataFormat: ResultDataFormat[] | null = null; - private readonly cache: Map>; + private readonly cache: Map>; constructor(source: IDatabaseDataSource) { super(source); @@ -32,10 +32,9 @@ export class ResultSetCacheAction extends DatabaseDataAction(key: SerializableKey, scope: string): T | undefined { + get(key: SerializableKey, scope: symbol): T | undefined { const hash = this.getHash(key); const scopedCache = this.cache.get(scope); - if (!scopedCache) { return; } @@ -43,7 +42,7 @@ export class ResultSetCacheAction extends DatabaseDataAction(key: SerializableKey, value: T, scope: string) { + set(key: SerializableKey, value: T, scope: symbol) { const hash = this.getHash(key); let scopedCache = this.cache.get(scope); if (!scopedCache) { - scopedCache = new Map(); + scopedCache = observable(new Map()); this.cache.set(scope, scopedCache); } scopedCache.set(hash, value); } - delete(key: SerializableKey, scope: string) { - const hash = ResultSetDataKeysUtils.serialize(key); + delete(key: SerializableKey, scope: symbol) { + const hash = this.getHash(key); const scopedCache = this.cache.get(scope); if (scopedCache) { @@ -75,6 +74,10 @@ export class ResultSetCacheAction extends DatabaseDataAction Date: Thu, 8 Feb 2024 11:51:53 +0800 Subject: [PATCH 27/37] CB-4457 review fixes --- .../Actions/IDatabaseDataCacheAction.ts | 6 +- .../Actions/ResultSet/ResultSetCacheAction.ts | 146 ++++++++++++++++++ .../Actions/ResultSet/ResultSetDataAction.ts | 4 + .../ResultSet/ResultSetDataKeysUtils.ts | 4 +- .../Actions/ResultSetCacheAction.ts | 84 ---------- .../packages/plugin-data-viewer/src/index.ts | 2 +- 6 files changed, 157 insertions(+), 89 deletions(-) create mode 100644 webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts delete mode 100644 webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataCacheAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataCacheAction.ts index bec9d872f0..e260829165 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataCacheAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/IDatabaseDataCacheAction.ts @@ -5,10 +5,12 @@ * 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 { +export interface IDatabaseDataCacheAction extends IDatabaseDataAction { has(key: TKey, scope: symbol): boolean; get(key: TKey, scope: symbol): T | undefined; - set(key: TKey, value: T, scope: symbol): void; + set(key: TKey, scope: symbol, value: T): void; delete(key: TKey, scope: symbol): void; } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts new file mode 100644 index 0000000000..b6d5b20839 --- /dev/null +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts @@ -0,0 +1,146 @@ +/* + * 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 + implements IDatabaseDataCacheAction +{ + static dataFormat = [ResultDataFormat.Resultset]; + + private readonly cache: Map>; + + constructor(source: IDatabaseDataSource, private readonly data: ResultSetDataAction) { + super(source); + + this.cache = new Map(); + + makeObservable(this, { + cache: observable, + }); + } + + get(key: IResultSetElementKey, scope: symbol): T | undefined { + const keyCache = this.getKeyCache(key); + if (!keyCache) { + return; + } + + return keyCache.get(scope); + } + + getRow(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(key: IResultSetElementKey, scope: symbol, value: T) { + const keyCache = this.getOrCreateKeyCache(key); + + keyCache.set(scope, value); + } + + setRow(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); + } + } + + 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; + } +} diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts index 8241f84652..fa4f451cfb 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts @@ -47,6 +47,10 @@ export class ResultSetDataAction extends DatabaseDataResultAction(a: T, b: T): boolean { + isEqual(a: T, b: T): boolean { if (a.index !== b.index) { return false; } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts deleted file mode 100644 index c6424b04a8..0000000000 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSetCacheAction.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 type { 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 { ResultSetDataKeysUtils, type SerializableKey } from './ResultSet/ResultSetDataKeysUtils'; - -@databaseDataAction() -export class ResultSetCacheAction extends DatabaseDataAction implements IDatabaseDataCacheAction { - static dataFormat: ResultDataFormat[] | null = null; - - private readonly cache: Map>; - - constructor(source: IDatabaseDataSource) { - super(source); - - this.cache = new Map(); - - makeObservable(this, { - cache: observable, - }); - } - - get(key: SerializableKey, scope: symbol): T | undefined { - const hash = this.getHash(key); - const scopedCache = this.cache.get(scope); - if (!scopedCache) { - return; - } - - return scopedCache.get(hash); - } - - has(key: SerializableKey, scope: symbol) { - const hash = this.getHash(key); - const scopedCache = this.cache.get(scope); - - if (!scopedCache) { - return false; - } - - return scopedCache.has(hash); - } - - set(key: SerializableKey, value: T, scope: symbol) { - const hash = this.getHash(key); - let scopedCache = this.cache.get(scope); - - if (!scopedCache) { - scopedCache = observable(new Map()); - this.cache.set(scope, scopedCache); - } - - scopedCache.set(hash, value); - } - - delete(key: SerializableKey, scope: symbol) { - const hash = this.getHash(key); - const scopedCache = this.cache.get(scope); - - if (scopedCache) { - scopedCache.delete(hash); - } - } - - dispose(): void { - this.cache.clear(); - } - - private getHash(key: SerializableKey) { - return ResultSetDataKeysUtils.serialize(key); - } -} diff --git a/webapp/packages/plugin-data-viewer/src/index.ts b/webapp/packages/plugin-data-viewer/src/index.ts index 6177aa5739..4088477cd1 100644 --- a/webapp/packages/plugin-data-viewer/src/index.ts +++ b/webapp/packages/plugin-data-viewer/src/index.ts @@ -43,7 +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/ResultSetCacheAction'; +export * from './DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction'; export * from './DatabaseDataModel/DatabaseDataAction'; export * from './DatabaseDataModel/DatabaseDataActions'; export * from './DatabaseDataModel/DatabaseDataFormat'; From 3177f9752a8077cc005b7e8706de5438526c2722 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Thu, 8 Feb 2024 14:29:24 +0400 Subject: [PATCH 28/37] CB-4457. Refactor after review. Added logic for delete --- .../bundles/io.cloudbeaver.server/schema/service.sql.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls index b646b3b848..b51bb1cd2f 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls @@ -94,7 +94,7 @@ type SQLResultColumn { } type SQLResultRowMetaData { - data: [Object] + data: [Object]! metaData: Object } From 38b591e82e5dd8467cbede8948cd9b7878d3e567 Mon Sep 17 00:00:00 2001 From: naumov Date: Thu, 8 Feb 2024 12:11:56 +0100 Subject: [PATCH 29/37] CB-4457 pass metadata in deleted rows --- .../DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts index d4181cccaa..4003608167 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts @@ -520,7 +520,7 @@ export class ResultSetEditAction extends DatabaseEditAction Date: Thu, 8 Feb 2024 13:13:06 +0100 Subject: [PATCH 30/37] CB-4457 check row for undefined --- .../DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts index 4003608167..f0ecf90b0e 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetEditAction.ts @@ -340,7 +340,7 @@ export class ResultSetEditAction extends DatabaseEditAction Date: Thu, 8 Feb 2024 14:22:25 +0100 Subject: [PATCH 31/37] CB-4457 pass metadata when editing json --- .../DatabaseDataModel/Actions/Document/DocumentDataAction.ts | 5 +++++ .../DatabaseDataModel/Actions/Document/DocumentEditAction.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts index d00c472487..c580623465 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts @@ -37,6 +37,11 @@ export class DocumentDataAction extends DatabaseDataResultAction row.data[0]?.id === documentId); + return row?.metaData; + } + getIdentifier(key: IDocumentElementKey): string { return key.index.toString(); } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts index 05af6b91ef..a32f6133b1 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentEditAction.ts @@ -181,6 +181,7 @@ export class DocumentEditAction extends DatabaseEditAction Date: Thu, 8 Feb 2024 19:36:46 +0400 Subject: [PATCH 32/37] CB-4457. Refactor edit, fix icons --- .../service/sql/WebSQLProcessor.java | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index 275b3efcd4..c378184e09 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -564,9 +564,12 @@ private DBSDataManipulator generateUpdateResultsDataBatch( .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 metaData = row.getMetaData().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 metaData; + if (row.getMetaData() != null) { + metaData = new HashMap<>(row.getMetaData()); + } else { + metaData = new HashMap<>(); + } if (finalRow.length == 0 || CommonUtils.isEmpty(updateValues)) { continue; @@ -656,6 +659,7 @@ private DBSDataManipulator generateUpdateResultsDataBatch( if (keyAttributes.length > 0 && !CommonUtils.isEmpty(deletedRows)) { for (WebSQLResultsRow row : deletedRows) { Object[] keyData = row.getData(); + Map keyMetaData = row.getMetaData(); if (keyData.length == 0) { continue; } @@ -663,20 +667,37 @@ private DBSDataManipulator generateUpdateResultsDataBatch( 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 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]); + } } } } @@ -711,8 +732,10 @@ public DBDDocument makeDocumentInputValue( if (plainValue instanceof 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 (((DBDDocument) plainValue).getDocumentId() != null) { + document = (DBDDocument) plainValue; + break; + } } keyMap.put(attr.getName(), plainValue); } From 549423d8304bb4c2e6f0744fb312675cd464bfe2 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Thu, 8 Feb 2024 20:25:25 +0400 Subject: [PATCH 33/37] CB-4457. Refactor makeDocumentInputValue, created new method for locator --- .../src/io/cloudbeaver/service/sql/WebSQLProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index c378184e09..995be53566 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -729,10 +729,10 @@ public DBDDocument makeDocumentInputValue( 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 - if (((DBDDocument) plainValue).getDocumentId() != null) { + if (dataContainer.isDocumentValid(dbdDocument)) { document = (DBDDocument) plainValue; break; } From 9af5005a083573fbfccf259e463fffe81344db8d Mon Sep 17 00:00:00 2001 From: naumov Date: Mon, 12 Feb 2024 12:28:29 +0100 Subject: [PATCH 34/37] CB-4457 try to get the current metadata for row --- .../DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts index fa4f451cfb..53bfef3dcc 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetDataAction.ts @@ -86,7 +86,7 @@ export class ResultSetDataAction extends DatabaseDataResultAction Date: Mon, 12 Feb 2024 13:12:43 +0100 Subject: [PATCH 35/37] CB-4457 clear cache on result update --- .../Actions/ResultSet/ResultSetCacheAction.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts index b6d5b20839..c1af786deb 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/ResultSet/ResultSetCacheAction.ts @@ -102,6 +102,10 @@ export class ResultSetCacheAction } } + afterResultUpdate() { + this.cache.clear(); + } + dispose(): void { this.cache.clear(); } From 78cbc6d3f24123dd3864c3cc1fd302022cea94fd Mon Sep 17 00:00:00 2001 From: naumov Date: Mon, 12 Feb 2024 13:55:05 +0100 Subject: [PATCH 36/37] CB-4457 remove extra check --- .../DatabaseDataModel/Actions/Document/DocumentDataAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts index c580623465..515b013c27 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/Actions/Document/DocumentDataAction.ts @@ -21,7 +21,7 @@ export class DocumentDataAction extends DatabaseDataResultAction row.data?.[0]) || []; + return this.result.data?.rowsWithMetaData?.map(row => row.data[0]) || []; } get count(): number { From 9e79b533ad896f3f9b2dd505d30a65b34337e663 Mon Sep 17 00:00:00 2001 From: DenisSinelnikov Date: Mon, 12 Feb 2024 21:32:23 +0400 Subject: [PATCH 37/37] CB-4457. Fixed npe --- .../service/sql/WebSQLQueryDataReceiver.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java index e9fc323fd2..8585e0c6d9 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryDataReceiver.java @@ -84,14 +84,16 @@ public void fetchRow(DBCSession session, DBCResultSet resultSet) throws DBCExcep binding.getMetaAttribute(), i); row[i] = cellValue; - Method[] methods = Objects.requireNonNull(cellValue).getClass().getMethods(); - for (Method method : methods) { - if (method.isAnnotationPresent(MetaData.class)){ - if (metaDataMap == null) { - metaDataMap = new HashMap<>(); + 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); } - Object value = method.invoke(cellValue); - metaDataMap.put(method.getAnnotation(MetaData.class).name(), value); } }