Skip to content

Commit 4d42e29

Browse files
committed
dbeaver/pro#9617 api for data-import settings
1 parent 36e954c commit 4d42e29

7 files changed

Lines changed: 173 additions & 3 deletions

File tree

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,4 +593,13 @@ public void setCredentialsSavedInSession(@Nullable Boolean credentialsSavedInSes
593593
this.credentialsSavedInSession = credentialsSavedInSession;
594594
}
595595

596+
/**
597+
* Database-dependent metadata describing the data import settings available for this connection
598+
*/
599+
@Property
600+
@NotNull
601+
public WebDataImportSettings getDataImportSettings() {
602+
return new WebDataImportSettings(dataSourceContainer);
603+
}
604+
596605
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* DBeaver - Universal Database Manager
3+
* Copyright (C) 2010-2026 DBeaver Corp and others
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package io.cloudbeaver.model;
18+
19+
import org.jkiss.code.NotNull;
20+
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
21+
import org.jkiss.dbeaver.model.meta.Property;
22+
import org.jkiss.dbeaver.model.sql.SQLDialectInsertReplaceMethod;
23+
import org.jkiss.dbeaver.model.sql.SQLDialectMetadata;
24+
import org.jkiss.utils.CommonUtils;
25+
26+
import java.util.Collections;
27+
import java.util.List;
28+
import java.util.stream.Collectors;
29+
30+
public class WebDataImportSettings {
31+
32+
public static final String SETTING_ON_DUPLICATE_KEY_METHOD = "onDuplicateKeyMethod";
33+
34+
@NotNull
35+
private final DBPDataSourceContainer dataSourceContainer;
36+
37+
public WebDataImportSettings(@NotNull DBPDataSourceContainer dataSourceContainer) {
38+
this.dataSourceContainer = dataSourceContainer;
39+
}
40+
41+
@Property
42+
@NotNull
43+
public List<WebDataImportSettingValueInfo> getReplaceMethods() {
44+
SQLDialectMetadata dialect = dataSourceContainer.getDriver().getScriptDialect();
45+
List<SQLDialectInsertReplaceMethod> replaceMethods = dialect.getSupportedInsertReplaceMethodsDescriptors();
46+
if (CommonUtils.isEmpty(replaceMethods)) {
47+
return Collections.emptyList();
48+
}
49+
return replaceMethods.stream()
50+
.map(method -> new WebDataImportSettingValueInfo(method.getId(), method.getLabel(), method.getDescription()))
51+
.collect(Collectors.toList());
52+
}
53+
}

server/bundles/io.cloudbeaver.server/schema/service.core.graphqls

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,25 @@ type ConnectionInfo {
570570

571571
"List of tools that can be used with this connection. Returns empty list if no tools are available"
572572
tools: [String!]! @since(version: "24.1.3")
573+
574+
"Database-dependent metadata describing the data import settings available for this connection"
575+
dataImportSettings: DataImportSettingsInfo! @since(version: "26.1.2")
576+
}
577+
578+
"Database-dependent metadata describing the data import settings available for a connection."
579+
type DataImportSettingsInfo {
580+
"Supported 'on duplicate key' replace methods for this connection's SQL dialect (setting id: 'onDuplicateKeyMethod')"
581+
replaceMethods: [DataImportSettingValueInfo!]!
582+
}
583+
584+
"Generic metadata of a single allowed value (option) of a data import setting"
585+
type DataImportSettingValueInfo {
586+
"Value ID. Passed back in the import query 'settings' map for the corresponding setting"
587+
id: ID!
588+
"Human readable value name"
589+
name: String!
590+
"Value description"
591+
description: String
573592
}
574593

575594
type ConnectionFolderInfo {

server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/DBWServiceDataTransfer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
2929
import io.cloudbeaver.service.sql.WebSQLProcessor;
3030
import io.cloudbeaver.service.sql.WebSQLResultsInfo;
3131
import org.jkiss.code.NotNull;
32+
import org.jkiss.code.Nullable;
3233
import org.jkiss.dbeaver.DBException;
3334
import org.jkiss.dbeaver.model.rm.RMConstants;
3435
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
3536

3637
import java.io.OutputStream;
3738
import java.nio.file.Path;
3839
import java.util.List;
40+
import java.util.Map;
3941

4042
/**
4143
* Web service implementation
@@ -64,6 +66,7 @@ WebAsyncTaskInfo asyncImportDataContainer(
6466
@NotNull String processorId,
6567
@NotNull Path path,
6668
@NotNull WebSQLResultsInfo webSQLResultsInfo,
69+
@Nullable Map<String, Object> settings,
6770
@NotNull WebSession webSession) throws DBWebException;
6871

6972
@NotNull

server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferImportServlet.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ protected void processServiceRequest(
9797
String contextId = JSONUtils.getString(variables, "contextId");
9898
String resultId = JSONUtils.getString(variables, "resultsId");
9999
String processorId = JSONUtils.getString(variables, "processorId");
100+
Map<String, Object> settings = JSONUtils.getObjectOrNull(variables, "settings");
100101

101102
if (projectId == null || connectionId == null || contextId == null || resultId == null || processorId == null) {
102103
throw new IllegalArgumentException("Missing required parameters");
@@ -122,7 +123,7 @@ protected void processServiceRequest(
122123
}
123124

124125
WebAsyncTaskInfo asyncImportDataContainer =
125-
dbwServiceDataTransfer.asyncImportDataContainer(processorId, filePath, webSQLResultsInfo, session);
126+
dbwServiceDataTransfer.asyncImportDataContainer(processorId, filePath, webSQLResultsInfo, settings, session);
126127
response.setContentType(HttpConstants.CONTENT_TYPE_JSON);
127128
Map<String, Object> parameters = new LinkedHashMap<>();
128129
parameters.put("id", asyncImportDataContainer.getId());

server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebServiceDataTransfer.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.cloudbeaver.DBWConstants;
2020
import io.cloudbeaver.DBWebException;
2121
import io.cloudbeaver.model.WebAsyncTaskInfo;
22+
import io.cloudbeaver.model.WebDataImportSettings;
2223
import io.cloudbeaver.model.session.WebAsyncTaskProcessor;
2324
import io.cloudbeaver.model.session.WebSession;
2425
import io.cloudbeaver.server.CBConstants;
@@ -237,6 +238,7 @@ public WebAsyncTaskInfo asyncImportDataContainer(
237238
@NotNull String processorId,
238239
@NotNull Path path,
239240
@NotNull WebSQLResultsInfo sqlContext,
241+
@Nullable Map<String, Object> settings,
240242
@NotNull WebSession webSession
241243
) throws DBWebException {
242244
webSession.addInfoMessage("Import data");
@@ -254,7 +256,7 @@ public void run(@NotNull DBRProgressMonitor monitor) throws InvocationTargetExce
254256
try {
255257
monitor.subTask("Import data using " + processor.getName());
256258
try {
257-
importData(monitor, processor, (DBSDataManipulator) dataContainer, path);
259+
importData(monitor, processor, (DBSDataManipulator) dataContainer, path, settings);
258260
} catch (Exception e) {
259261
if (e instanceof DBException) {
260262
throw e;
@@ -342,7 +344,8 @@ private void importData(
342344
@NotNull DBRProgressMonitor monitor,
343345
@NotNull DataTransferProcessorDescriptor processor,
344346
@NotNull DBSDataManipulator dataContainer,
345-
@NotNull Path path
347+
@NotNull Path path,
348+
@Nullable Map<String, Object> settings
346349
) throws DBException {
347350
IDataTransferProcessor processorInstance = processor.getInstance();
348351

@@ -354,6 +357,7 @@ private void importData(
354357
DatabaseConsumerSettings databaseConsumerSettings = new DatabaseConsumerSettings();
355358
databaseConsumerSettings.setContainer((DBSObjectContainer) dataContainer.getDataSource());
356359
databaseConsumerSettings.setEnableQmLogging(true);
360+
applyImportSettings(databaseConsumerSettings, settings);
357361
consumer.setSettings(databaseConsumerSettings);
358362

359363
StreamProducerSettings producerSettings = new StreamProducerSettings();
@@ -384,4 +388,19 @@ private void importData(
384388
}
385389
}
386390

391+
private void applyImportSettings(
392+
@NotNull DatabaseConsumerSettings consumerSettings,
393+
@Nullable Map<String, Object> settings
394+
) {
395+
if (CommonUtils.isEmpty(settings)) {
396+
return;
397+
}
398+
// todo add more import settings here
399+
String onDuplicateKeyMethod = CommonUtils.toString(
400+
settings.get(WebDataImportSettings.SETTING_ON_DUPLICATE_KEY_METHOD), null);
401+
if (!CommonUtils.isEmpty(onDuplicateKeyMethod)) {
402+
consumerSettings.setOnDuplicateKeyInsertMethodId(onDuplicateKeyMethod);
403+
}
404+
}
405+
387406
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* DBeaver - Universal Database Manager
3+
* Copyright (C) 2010-2026 DBeaver Corp and others
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package io.cloudbeaver.test.platform.connection;
18+
19+
import io.cloudbeaver.test.platform.CloudbeaverDBTest;
20+
import org.jkiss.dbeaver.model.data.json.JSONUtils;
21+
import org.junit.jupiter.api.Assertions;
22+
import org.junit.jupiter.api.Test;
23+
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
public class ConnectionDataImportSettingsTest extends CloudbeaverDBTest {
28+
29+
private static final String GQL_CONNECTION_DATA_IMPORT_SETTINGS = """
30+
query connectionInfo($projectId: ID!, $connectionId: ID!) {
31+
result: connectionInfo(projectId: $projectId, id: $connectionId) {
32+
id
33+
dataImportSettings {
34+
replaceMethods {
35+
id
36+
name
37+
description
38+
}
39+
}
40+
}
41+
}""";
42+
43+
@Test
44+
public void connectionExposesDataImportSettings() throws Exception {
45+
Map<String, Object> connection = client.sendQuery(
46+
GQL_CONNECTION_DATA_IMPORT_SETTINGS,
47+
Map.of(
48+
"projectId", globalProject.getId(),
49+
"connectionId", databaseContainer.getId()
50+
)
51+
);
52+
Assertions.assertNotNull(connection);
53+
Assertions.assertEquals(databaseContainer.getId(), JSONUtils.getString(connection, "id"));
54+
55+
Map<String, Object> dataImportSettings = JSONUtils.getObjectOrNull(connection, "dataImportSettings");
56+
Assertions.assertNotNull(dataImportSettings, "dataImportSettings must be present on a connection");
57+
58+
List<Map<String, Object>> replaceMethods = JSONUtils.getObjectList(dataImportSettings, "replaceMethods");
59+
Assertions.assertNotNull(replaceMethods, "replaceMethods must be a non-null list");
60+
61+
for (Map<String, Object> replaceMethod : replaceMethods) {
62+
Assertions.assertNotNull(JSONUtils.getString(replaceMethod, "id"), "replace method id must not be null");
63+
Assertions.assertNotNull(JSONUtils.getString(replaceMethod, "name"), "replace method name must not be null");
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)