Skip to content

Commit 488dcdd

Browse files
authored
Merge pull request #498 from ChinthakaJ98/dss-mapping-generation
2 parents f2d8b51 + 5877121 commit 488dcdd

File tree

8 files changed

+356
-7
lines changed

8 files changed

+356
-7
lines changed

org.eclipse.lemminx/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>org.wso2.language.server</groupId>
55
<artifactId>mi-language-server-parent</artifactId>
6-
<version>0.24.0-wso2v85</version>
6+
<version>0.24.0-wso2v86-SNAPSHOT</version>
77
<relativePath>../pom.xml</relativePath>
88
</parent>
99
<name>MI Language Server</name>

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/SynapseLanguageService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.eclipse.lemminx.customservice.synapse.dataService.QueryGenerator;
4242
import org.eclipse.lemminx.customservice.synapse.dataService.CheckDBDriverRequestParams;
4343
import org.eclipse.lemminx.customservice.synapse.dataService.CheckDBDriverResponseParams;
44+
import org.eclipse.lemminx.customservice.synapse.dataService.MappingsGenRequestParams;
4445
import org.eclipse.lemminx.customservice.synapse.dataService.ModifyDriverRequestParams;
4546
import org.eclipse.lemminx.customservice.synapse.dataService.QueryGenRequestParams;
4647
import org.eclipse.lemminx.customservice.synapse.db.DBConnectionTestParams;
@@ -788,6 +789,13 @@ public CompletableFuture<List<String>> pdfToImagesBase64(PdfToImagesRequest para
788789
return CompletableFuture.supplyAsync(() -> Utils.pdfToImage(param.getBase64()));
789790
}
790791

792+
@Override
793+
public CompletableFuture<List<List<Object>>> getInputOutputMappings(MappingsGenRequestParams param) {
794+
795+
return CompletableFuture.supplyAsync(() -> Constant.INPUT.equals(param.type) ?
796+
QueryGenerator.getInputMappings(param.query) : QueryGenerator.getOutputMappings(param));
797+
}
798+
791799
public String getProjectUri() {
792800
return projectUri;
793801
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/ISynapseLanguageService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.eclipse.lemminx.customservice.synapse.connectors.generate.ConnectorGeneratorResponse;
3434
import org.eclipse.lemminx.customservice.synapse.dataService.CheckDBDriverRequestParams;
3535
import org.eclipse.lemminx.customservice.synapse.dataService.CheckDBDriverResponseParams;
36+
import org.eclipse.lemminx.customservice.synapse.dataService.MappingsGenRequestParams;
3637
import org.eclipse.lemminx.customservice.synapse.dataService.ModifyDriverRequestParams;
3738
import org.eclipse.lemminx.customservice.synapse.dataService.QueryGenRequestParams;
3839
import org.eclipse.lemminx.customservice.synapse.db.DBConnectionTestParams;
@@ -294,4 +295,7 @@ public interface ISynapseLanguageService {
294295

295296
@JsonRequest
296297
CompletableFuture<DependencyStatusResponse> getDependencyStatusList();
298+
299+
@JsonRequest
300+
CompletableFuture<List<List<Object>>> getInputOutputMappings(MappingsGenRequestParams param);
297301
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com).
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License v2.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/legal/epl-v20.html
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* WSO2 LLC - support for WSO2 Micro Integrator Configuration
13+
*/
14+
15+
package org.eclipse.lemminx.customservice.synapse.dataService;
16+
17+
public class MappingsGenRequestParams {
18+
19+
public String query;
20+
public String className;
21+
public String username;
22+
public String password;
23+
public String url;
24+
public String type;
25+
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/dataService/QueryGenerateUtils.java

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,20 @@
1414

1515
package org.eclipse.lemminx.customservice.synapse.dataService;
1616

17+
import java.sql.Connection;
18+
import java.sql.PreparedStatement;
19+
import java.sql.ResultSetMetaData;
20+
import java.sql.SQLException;
21+
import java.sql.Types;
22+
import java.util.ArrayList;
1723
import java.util.HashMap;
24+
import java.util.LinkedHashMap;
25+
import java.util.List;
1826
import java.util.Map;
27+
import java.util.logging.Level;
1928
import java.util.logging.Logger;
20-
import java.sql.Types;
29+
import java.util.regex.Matcher;
30+
import java.util.regex.Pattern;
2131

2232
import org.w3c.dom.Document;
2333
import org.w3c.dom.Element;
@@ -198,4 +208,139 @@ private static void updateQueryParamTypes() {
198208
qnameTypeMap.put(Types.DATE, "date");
199209
}
200210

211+
/**
212+
* Extract input columns from the given SQL query.
213+
*
214+
* @param query SQL query string
215+
*
216+
* @return List of input column names
217+
*/
218+
public static List<String> getInputColumns(String query) {
219+
List<String> columns = new ArrayList<>();
220+
221+
if (query == null || query.trim().isEmpty()) {
222+
return columns;
223+
}
224+
225+
String lower = query.toLowerCase().trim();
226+
227+
// Handle SELECT ... WHERE ...
228+
if (lower.contains("select") && lower.contains("from") && lower.contains("where")) {
229+
String wherePart = query.substring(lower.lastIndexOf("where") + 5).trim();
230+
String[] conditions = wherePart.split("(?i)\\s+and\\s+|\\s+or\\s+");
231+
232+
for (String cond : conditions) {
233+
if (cond.contains("=")) {
234+
columns.add(cond.split("=")[0].trim());
235+
}
236+
}
237+
}
238+
239+
// Handle INSERT INTO ... VALUES (...)
240+
else if (lower.contains("insert") && lower.contains("into") && lower.contains("values")) {
241+
Pattern pattern = Pattern.compile("\\(([^)]+)\\)");
242+
Matcher matcher = pattern.matcher(query);
243+
244+
if (matcher.find()) {
245+
String inside = matcher.group(1);
246+
inside = inside.replace(":", "");
247+
String[] parts = inside.split(",");
248+
249+
for (String part : parts) {
250+
columns.add(part.trim());
251+
}
252+
}
253+
}
254+
255+
// Handle UPDATE ... SET ... WHERE ...
256+
else if (lower.contains("update") && lower.contains("set")) {
257+
String setPart = query.substring(lower.indexOf("set") + 3);
258+
setPart = setPart.replaceAll("(?i)where", ",");
259+
260+
String[] parts = setPart.split(",");
261+
262+
for (String part : parts) {
263+
if (part.contains("=")) {
264+
columns.add(part.split("=")[0].trim());
265+
}
266+
}
267+
}
268+
269+
// Handle DELETE FROM ... WHERE ...
270+
else if (lower.contains("delete") && lower.contains("from") && lower.contains("where")) {
271+
String wherePart = query.substring(lower.lastIndexOf("where") + 5);
272+
String[] conditions = wherePart.split("(?i)\\s+and\\s+|\\s+or\\s+");
273+
274+
for (String cond : conditions) {
275+
if (cond.contains("=")) {
276+
columns.add(cond.split("=")[0].trim());
277+
}
278+
}
279+
}
280+
281+
return columns;
282+
}
283+
284+
/**
285+
* Extract output columns from the given SQL query.
286+
*
287+
* @param query SQL query string
288+
* @param connection JDBC connection to execute the query if needed
289+
*
290+
* @return Map of output column names and their types
291+
* @throws SQLException if a database access error occurs
292+
*/
293+
public static Map<String, String> getOutputColumns(String query, Connection connection) throws SQLException {
294+
Map<String, String> columns = new LinkedHashMap<>();
295+
296+
if (query == null || query.trim().isEmpty()) {
297+
return columns;
298+
}
299+
300+
String lower = query.toLowerCase();
301+
302+
// Ignore INSERT, UPDATE and DELETE
303+
if (!lower.startsWith("select")) {
304+
return columns;
305+
}
306+
307+
if (lower.contains("select") && lower.contains("from")) {
308+
int selectIndex = lower.lastIndexOf("select") + 6;
309+
int fromIndex = lower.lastIndexOf("from");
310+
311+
if (selectIndex < fromIndex) {
312+
String mappingPart = query.substring(selectIndex, fromIndex).trim();
313+
String[] parts = mappingPart.split(",");
314+
315+
// Handle SELECT *
316+
if (parts.length == 1 && parts[0].trim().equals("*")) {
317+
if (connection != null) {
318+
try (PreparedStatement stmt = connection.prepareStatement(
319+
query.replaceAll("(?i)\\s+where\\s+.*$", ""))) {
320+
ResultSetMetaData meta = stmt.getMetaData();
321+
322+
int columnCount = meta.getColumnCount();
323+
for (int i = 1; i <= columnCount; i++) {
324+
columns.put(meta.getColumnLabel(i), qnameTypeMap.get(meta.getColumnType(i)));
325+
}
326+
} catch (SQLException e) {
327+
LOGGER.log(Level.SEVERE, "Error retrieving columns for the query." + e);
328+
throw e;
329+
}
330+
} else {
331+
LOGGER.log(Level.SEVERE,"Connection is null, cannot retrieve columns for SELECT * query.");
332+
throw new SQLException("Cannot execute select query as the connection is null.");
333+
}
334+
}
335+
// Handle SELECT col1, col2, ...
336+
else {
337+
for (String part : parts) {
338+
columns.put(part.trim(), "string");
339+
}
340+
}
341+
}
342+
}
343+
return columns;
344+
}
345+
201346
}

org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/customservice/synapse/dataService/QueryGenerator.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,66 @@ public static boolean modifyDriverInClassPath(String addDriverPath, String remov
244244
return removeDriverFromClassPath(removeDriverPath) && addDriverToClassPath(addDriverPath, className);
245245
}
246246

247+
/**
248+
* Generate input mappings for a query
249+
*
250+
* @param query SQL query string
251+
*
252+
* @return List of input mappings for the query
253+
*/
254+
public static List<List<Object>> getInputMappings(String query) {
255+
256+
List<String> columns = QueryGenerateUtils.getInputColumns(query);
257+
List<List<Object>> mappingsList = new ArrayList<>();
258+
for (String column : columns) {
259+
mappingsList.add(Arrays.asList(column, column, "SCALAR", "STRING", "", "IN", 0, new ArrayList<>()));
260+
}
261+
return mappingsList;
262+
}
263+
264+
/**
265+
* Generate output mappings for a query
266+
*
267+
* @param requestParams SQL query and connection parameters object
268+
*
269+
* @return List of output mappings for the query
270+
*/
271+
public static List<List<Object>> getOutputMappings(MappingsGenRequestParams requestParams) {
272+
273+
Connection connection = null;
274+
List<List<Object>> mappingsList = new ArrayList<>();
275+
276+
if (StringUtils.isNotBlank(requestParams.className)) {
277+
DBConnectionTester dbConnectionTester = new DBConnectionTester();
278+
try {
279+
connection = dbConnectionTester.getConnection(requestParams.url, requestParams.username,
280+
requestParams.password, requestParams.className);
281+
} catch (Exception e) {
282+
LOGGER.log(Level.SEVERE, "Error occurred while creating DB connection.", e);
283+
}
284+
}
285+
try {
286+
Map<String, String> columns = QueryGenerateUtils.getOutputColumns(requestParams.query, connection);
287+
for (Map.Entry<String, String> column : columns.entrySet()) {
288+
mappingsList.add(Arrays.asList("Element", "", new ArrayList<>(), "Column",
289+
column.getKey().substring(0, 1).toUpperCase() + column.getKey().substring(1), "", "",
290+
column.getKey(), "", "Scalar", "", column.getValue(), false, "", "", "Scalar", false, false));
291+
}
292+
return mappingsList;
293+
} catch (Exception e) {
294+
LOGGER.log(Level.SEVERE, "Error occurred while generating output mappings for query.", e);
295+
return null;
296+
} finally {
297+
if (connection != null) {
298+
try {
299+
connection.close();
300+
} catch (SQLException e) {
301+
LOGGER.log(Level.SEVERE, "Error while closing DB connection.", e);
302+
}
303+
}
304+
}
305+
}
306+
247307
/**
248308
* Generate resource and query for select all operation
249309
*

0 commit comments

Comments
 (0)