feat: Where condition helper library using H2 in memory database (#7592)
This commit is contained in:
parent
eaa9d783df
commit
659d7c3866
|
|
@ -126,6 +126,12 @@
|
|||
<version>2.4.7</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.200</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.external.plugins;
|
||||
package com.appsmith.external.constants;
|
||||
|
||||
public enum Op {
|
||||
public enum ConditionalOperator {
|
||||
LT,
|
||||
LTE,
|
||||
EQ,
|
||||
61
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Condition.java
vendored
Normal file
61
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Condition.java
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package com.appsmith.external.models;
|
||||
|
||||
import com.appsmith.external.constants.ConditionalOperator;
|
||||
import com.appsmith.external.constants.DataType;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.appsmith.external.helpers.DataTypeStringUtils.stringToKnownDataTypeConverter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Condition {
|
||||
|
||||
String path;
|
||||
|
||||
ConditionalOperator operator;
|
||||
|
||||
String value;
|
||||
|
||||
@JsonIgnore
|
||||
DataType valueDataType;
|
||||
|
||||
public Condition(String path, String operator, String value) {
|
||||
this.path = path;
|
||||
this.operator = ConditionalOperator.valueOf(operator);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static List<Condition> addValueDataType(List<Condition> conditionList) {
|
||||
|
||||
return conditionList
|
||||
.stream()
|
||||
.map(condition -> {
|
||||
String value = condition.getValue();
|
||||
DataType dataType = stringToKnownDataTypeConverter(value);
|
||||
condition.setValueDataType(dataType);
|
||||
return condition;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Boolean isValid(Condition condition) {
|
||||
|
||||
if (StringUtils.isEmpty(condition.getPath()) ||
|
||||
(condition.getOperator() == null) ||
|
||||
StringUtils.isEmpty(condition.getValue())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
431
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/FilterDataService.java
vendored
Normal file
431
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/FilterDataService.java
vendored
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
package com.appsmith.external.services;
|
||||
|
||||
import com.appsmith.external.constants.ConditionalOperator;
|
||||
import com.appsmith.external.constants.DataType;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
|
||||
import com.appsmith.external.models.Condition;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.appsmith.external.helpers.DataTypeStringUtils.stringToKnownDataTypeConverter;
|
||||
import static com.appsmith.external.models.Condition.addValueDataType;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FilterDataService {
|
||||
|
||||
private static FilterDataService instance = null;
|
||||
private ObjectMapper objectMapper;
|
||||
private Connection connection;
|
||||
|
||||
private static final String URL = "jdbc:h2:mem:filterDb";
|
||||
|
||||
private static final Map<DataType, String> SQL_DATATYPE_MAP = Map.of(
|
||||
DataType.INTEGER, "INT",
|
||||
DataType.LONG, "BIGINT",
|
||||
DataType.FLOAT, "REAL",
|
||||
DataType.DOUBLE, "DOUBLE",
|
||||
DataType.BOOLEAN, "BOOLEAN",
|
||||
DataType.STRING, "VARCHAR"
|
||||
);
|
||||
|
||||
private static final Map<ConditionalOperator, String> SQL_OPERATOR_MAP = Map.of(
|
||||
ConditionalOperator.LT, "<",
|
||||
ConditionalOperator.LTE, "<=",
|
||||
ConditionalOperator.EQ, "=",
|
||||
ConditionalOperator.NOT_EQ, "<>",
|
||||
ConditionalOperator.GT, ">",
|
||||
ConditionalOperator.GTE, ">=",
|
||||
ConditionalOperator.IN, "IN",
|
||||
ConditionalOperator.NOT_IN, "NOT IN"
|
||||
);
|
||||
|
||||
private FilterDataService() {
|
||||
|
||||
objectMapper = new ObjectMapper();
|
||||
|
||||
try {
|
||||
connection = DriverManager.getConnection(URL);
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "Failed to connect to the in memory database. Unable to perform filtering");
|
||||
}
|
||||
}
|
||||
|
||||
public static FilterDataService getInstance() {
|
||||
|
||||
if (instance == null) {
|
||||
instance = new FilterDataService();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public ArrayNode filterData(ArrayNode items, List<Condition> conditionList) {
|
||||
|
||||
if (items == null || items.size() == 0) {
|
||||
return items;
|
||||
}
|
||||
|
||||
if (!validConditionList(conditionList)) {
|
||||
throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR, "Conditions for filtering were incomplete or incorrect.");
|
||||
}
|
||||
|
||||
List<Condition> conditions = addValueDataType(conditionList);
|
||||
|
||||
// Generate the schema of the table using the first object
|
||||
JsonNode jsonNode = items.get(0);
|
||||
|
||||
Map<String, DataType> schema = generateSchema(jsonNode);
|
||||
|
||||
String tableName = generateTable(schema);
|
||||
|
||||
// insert the data
|
||||
insertData(tableName, items, schema);
|
||||
|
||||
// Filter the data
|
||||
List<Map<String, Object>> finalResults = executeFilterQuery(tableName, conditions);
|
||||
|
||||
// Now that the data has been filtered. Clean Up. Drop the table
|
||||
dropTable(tableName);
|
||||
|
||||
ArrayNode finalResultsNode = objectMapper.valueToTree(finalResults);
|
||||
|
||||
return finalResultsNode;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> executeFilterQuery(String tableName, List<Condition> conditions) {
|
||||
StringBuilder sb = new StringBuilder("SELECT * FROM " + tableName);
|
||||
|
||||
String whereClause = generateWhereClause(conditions);
|
||||
sb.append(whereClause);
|
||||
|
||||
sb.append(";");
|
||||
|
||||
String selectQuery = sb.toString();
|
||||
log.debug("{} : Executing Query on H2 : {}", Thread.currentThread().getName(), selectQuery);
|
||||
|
||||
List<Map<String, Object>> rowsList = new ArrayList<>(50);
|
||||
|
||||
Connection conn = checkAndGetConnection();
|
||||
|
||||
try {
|
||||
Statement statement = conn.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(selectQuery);
|
||||
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
int colCount = metaData.getColumnCount();
|
||||
|
||||
while (resultSet.next()) {
|
||||
Map<String, Object> row = new LinkedHashMap<>(colCount);
|
||||
for (int i = 1; i <= colCount; i++) {
|
||||
row.put(metaData.getColumnName(i), resultSet.getObject(i));
|
||||
}
|
||||
rowsList.add(row);
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
// Getting a SQL Exception here means that our generated query is incorrect. Raise an alarm!
|
||||
log.error(e.getMessage());
|
||||
throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "Filtering failure seen : " + e.getMessage());
|
||||
}
|
||||
|
||||
return rowsList;
|
||||
}
|
||||
|
||||
private String generateWhereClause(List<Condition> conditions) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Boolean firstCondition = true;
|
||||
for (Condition condition : conditions) {
|
||||
|
||||
if (firstCondition) {
|
||||
// Append the WHERE keyword before adding the conditions
|
||||
sb.append(" WHERE ");
|
||||
firstCondition = false;
|
||||
} else {
|
||||
// This is not the first condition. Append an `AND` before adding the next condition
|
||||
sb.append(" AND ");
|
||||
}
|
||||
|
||||
String path = condition.getPath();
|
||||
ConditionalOperator operator = condition.getOperator();
|
||||
String value = condition.getValue();
|
||||
|
||||
String sqlOp = SQL_OPERATOR_MAP.get(operator);
|
||||
if (sqlOp == null) {
|
||||
throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR,
|
||||
operator.toString() + " is not supported currently for filtering.");
|
||||
}
|
||||
|
||||
sb.append(path);
|
||||
sb.append(" ");
|
||||
sb.append(sqlOp);
|
||||
sb.append(" ");
|
||||
|
||||
// These are array operations. Convert value into appropriate format and then append
|
||||
if (operator == ConditionalOperator.IN || operator == ConditionalOperator.NOT_IN) {
|
||||
|
||||
StringBuilder valueBuilder = new StringBuilder("(");
|
||||
|
||||
// The array could be an array of Strings
|
||||
if (value.contains("\"")) {
|
||||
try {
|
||||
List<String> stringValues = objectMapper.readValue(value, List.class);
|
||||
List<String> updatedStringValues = stringValues.stream().map(stringValue -> "\'" + stringValue + "\'").collect(Collectors.toList());
|
||||
String finalValues = String.join(",", updatedStringValues);
|
||||
valueBuilder.append(finalValues);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
// Removes the outer square brackets from the string to leave behind just the values separated by comma
|
||||
String trimmedValue = value.replaceAll("^\\[|]$", "");
|
||||
valueBuilder.append(trimmedValue);
|
||||
}
|
||||
|
||||
valueBuilder.append(")");
|
||||
value = valueBuilder.toString();
|
||||
sb.append(value);
|
||||
|
||||
} else {
|
||||
// Since the value is not an array, surround the same with single quotes and append
|
||||
sb.append("'");
|
||||
sb.append(value);
|
||||
sb.append("'");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// INSERT INTO tableName (columnName1, columnName2) VALUES (data1, data2)
|
||||
public void insertData(String tableName, ArrayNode items, Map<String, DataType> schema) {
|
||||
|
||||
List<String> columnNames = schema.keySet().stream().collect(Collectors.toList());
|
||||
|
||||
StringBuilder insertQueryBuilder = new StringBuilder("INSERT INTO ");
|
||||
insertQueryBuilder.append(tableName);
|
||||
|
||||
StringBuilder columnNamesBuilder = new StringBuilder("(");
|
||||
columnNamesBuilder.append(String.join(", ", columnNames));
|
||||
columnNamesBuilder.append(")");
|
||||
|
||||
insertQueryBuilder.append(columnNamesBuilder);
|
||||
insertQueryBuilder.append(" VALUES ");
|
||||
|
||||
StringBuilder valuesMasterBuilder = new StringBuilder();
|
||||
|
||||
int counter = 0;
|
||||
for (JsonNode item : items) {
|
||||
|
||||
// If the number of values inserted is greater than 1000, the insert would fail. Once we have reached 1000
|
||||
// rows, execute the insert for rows so far and start afresh for the rest of the rows
|
||||
if (counter == 1000) {
|
||||
String insertQueryString = finalInsertQueryString(insertQueryBuilder.toString(), valuesMasterBuilder);
|
||||
executeDbQuery(insertQueryString);
|
||||
|
||||
// Reset the values builder and counter for new insert queries.
|
||||
valuesMasterBuilder = new StringBuilder();
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
StringBuilder valuesBuilder = new StringBuilder();
|
||||
|
||||
if (counter != 0) {
|
||||
// If not the first row, add a separator between rows
|
||||
valuesBuilder.append(",");
|
||||
}
|
||||
|
||||
// Start the row
|
||||
valuesBuilder.append("(");
|
||||
|
||||
Boolean firstEntry = true;
|
||||
for (String columnName : columnNames) {
|
||||
|
||||
if (!firstEntry) {
|
||||
// Add a separator before adding a new entry
|
||||
valuesBuilder.append(",");
|
||||
} else {
|
||||
// For future iterations, set flag to false
|
||||
firstEntry = false;
|
||||
}
|
||||
|
||||
JsonNode fieldNode = item.get(columnName);
|
||||
if (fieldNode != null) {
|
||||
valuesBuilder.append("'");
|
||||
valuesBuilder.append(fieldNode.asText());
|
||||
valuesBuilder.append("'");
|
||||
}
|
||||
}
|
||||
|
||||
// End the row
|
||||
valuesBuilder.append(")");
|
||||
|
||||
valuesMasterBuilder.append(valuesBuilder);
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (valuesMasterBuilder.length() > 0) {
|
||||
String insertQueryString = finalInsertQueryString(insertQueryBuilder.toString(), valuesMasterBuilder);
|
||||
executeDbQuery(insertQueryString);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeDbQuery(String query) {
|
||||
|
||||
Connection conn = checkAndGetConnection();
|
||||
|
||||
try {
|
||||
conn.createStatement().execute(query);
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
// Getting a SQL Exception here means that our generated query is incorrect. Raise an alarm!
|
||||
throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "Filtering failure seen during insertion of data : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String finalInsertQueryString(String partialInsertQuery, StringBuilder valuesBuilder) {
|
||||
|
||||
StringBuilder insertQueryBuilder = new StringBuilder(partialInsertQuery);
|
||||
|
||||
insertQueryBuilder.append(valuesBuilder);
|
||||
insertQueryBuilder.append(";");
|
||||
|
||||
String finalInsertQuery = insertQueryBuilder.toString();
|
||||
|
||||
return finalInsertQuery;
|
||||
}
|
||||
|
||||
private Connection checkAndGetConnection() {
|
||||
try {
|
||||
if (connection == null || connection.isClosed() || !connection.isValid(5)) {
|
||||
connection = DriverManager.getConnection(URL);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "Failed to connect to the in memory database. Unable to perform filtering");
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
public String generateTable(Map<String, DataType> schema) {
|
||||
|
||||
// Generate table name
|
||||
String generateUniqueId = new ObjectId().toString().toUpperCase();
|
||||
|
||||
// Appending tbl_ before the generated unique id since using the string directly was throwing a SQL error
|
||||
// which I couldnt solve. Just appending a string to it though works perfectly.
|
||||
String tableName = new StringBuilder("tbl_").append(generateUniqueId).toString();
|
||||
|
||||
StringBuilder sb = new StringBuilder("CREATE TABLE ");
|
||||
|
||||
sb.append(tableName);
|
||||
|
||||
sb.append(" (");
|
||||
|
||||
Boolean columnsAdded = false;
|
||||
for (Map.Entry<String, DataType> entry : schema.entrySet()) {
|
||||
|
||||
if (columnsAdded) {
|
||||
// If columns have been added before, add a separator
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
String fieldName = entry.getKey();
|
||||
DataType dataType = entry.getValue();
|
||||
|
||||
String sqlDataType = SQL_DATATYPE_MAP.get(dataType);
|
||||
if (sqlDataType == null) {
|
||||
// the data type recognized does not have a native support in appsmith right now
|
||||
// default to String
|
||||
sqlDataType = SQL_DATATYPE_MAP.get(DataType.STRING);
|
||||
}
|
||||
columnsAdded = true;
|
||||
sb.append(fieldName);
|
||||
sb.append(" ");
|
||||
sb.append(sqlDataType);
|
||||
}
|
||||
|
||||
sb.append(");");
|
||||
|
||||
String createTableQuery = sb.toString();
|
||||
|
||||
executeDbQuery(createTableQuery);
|
||||
|
||||
return tableName;
|
||||
|
||||
}
|
||||
|
||||
public void dropTable(String tableName) {
|
||||
|
||||
String dropTableQuery = "DROP TABLE " + tableName + ";";
|
||||
|
||||
executeDbQuery(dropTableQuery);
|
||||
}
|
||||
|
||||
|
||||
private Map<String, DataType> generateSchema(JsonNode jsonNode) {
|
||||
|
||||
Iterator<String> fieldNamesIterator = jsonNode.fieldNames();
|
||||
/*
|
||||
* For an object of the following type :
|
||||
* {
|
||||
* "field1" : "stringValue",
|
||||
* "field2" : "true",
|
||||
* "field3" : "12"
|
||||
* }
|
||||
*
|
||||
* The schema generated would be a Map as follows :
|
||||
* {
|
||||
* field1 : DataType.STRING
|
||||
* field2 : DataType.BOOLEAN
|
||||
* field3 : DataType.INTEGER
|
||||
* }
|
||||
*/
|
||||
Map<String, DataType> schema = Stream.generate(() -> null)
|
||||
.takeWhile(x -> fieldNamesIterator.hasNext())
|
||||
.map(n -> fieldNamesIterator.next())
|
||||
.collect(Collectors.toMap(
|
||||
Function.identity(),
|
||||
name -> {
|
||||
String value = jsonNode.get(name).asText();
|
||||
DataType dataType = stringToKnownDataTypeConverter(value);
|
||||
return dataType;
|
||||
}));
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
|
||||
public boolean validConditionList(List<Condition> conditionList) {
|
||||
|
||||
return conditionList
|
||||
.stream()
|
||||
.allMatch(condition -> Condition.isValid(condition));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
package com.appsmith.external.services;
|
||||
|
||||
import com.appsmith.external.constants.DataType;
|
||||
import com.appsmith.external.models.Condition;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class FilterDataServiceTest {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final FilterDataService filterDataService = FilterDataService.getInstance();
|
||||
|
||||
@Test
|
||||
public void testGenerateTable() {
|
||||
Map<String, DataType> schema = Map.of(
|
||||
"id", DataType.INTEGER,
|
||||
"name", DataType.STRING,
|
||||
"status", DataType.BOOLEAN
|
||||
);
|
||||
|
||||
String table = filterDataService.generateTable(schema);
|
||||
|
||||
assertThat(table).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterSingleCondition() {
|
||||
String data = "[\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2381224,\n" +
|
||||
" \"email\": \"michael.lawson@reqres.in\",\n" +
|
||||
" \"userName\": \"Michael Lawson\",\n" +
|
||||
" \"productName\": \"Chicken Sandwich\",\n" +
|
||||
" \"orderAmount\": 4.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2736212,\n" +
|
||||
" \"email\": \"lindsay.ferguson@reqres.in\",\n" +
|
||||
" \"userName\": \"Lindsay Ferguson\",\n" +
|
||||
" \"productName\": \"Tuna Salad\",\n" +
|
||||
" \"orderAmount\": 9.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 6788734,\n" +
|
||||
" \"email\": \"tobias.funke@reqres.in\",\n" +
|
||||
" \"userName\": \"Tobias Funke\",\n" +
|
||||
" \"productName\": \"Beef steak\",\n" +
|
||||
" \"orderAmount\": 19.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
try {
|
||||
ArrayNode items = (ArrayNode) objectMapper.readTree(data);
|
||||
|
||||
List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
Condition condition = new Condition("orderAmount", "LT", "15");
|
||||
conditionList.add(condition);
|
||||
|
||||
ArrayNode filteredData = filterDataService.filterData(items, conditionList);
|
||||
|
||||
assertEquals(filteredData.size(), 2);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterMultipleConditions() {
|
||||
String data = "[\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2381224,\n" +
|
||||
" \"email\": \"michael.lawson@reqres.in\",\n" +
|
||||
" \"userName\": \"Michael Lawson\",\n" +
|
||||
" \"productName\": \"Chicken Sandwich\",\n" +
|
||||
" \"orderAmount\": 4.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2736212,\n" +
|
||||
" \"email\": \"lindsay.ferguson@reqres.in\",\n" +
|
||||
" \"userName\": \"Lindsay Ferguson\",\n" +
|
||||
" \"productName\": \"Tuna Salad\",\n" +
|
||||
" \"orderAmount\": 9.99,\n" +
|
||||
" \"orderStatus\": \"NOT READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 6788734,\n" +
|
||||
" \"email\": \"tobias.funke@reqres.in\",\n" +
|
||||
" \"userName\": \"Tobias Funke\",\n" +
|
||||
" \"productName\": \"Beef steak\",\n" +
|
||||
" \"orderAmount\": 19.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
try {
|
||||
ArrayNode items = (ArrayNode) objectMapper.readTree(data);
|
||||
|
||||
List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
Condition condition = new Condition("orderAmount", "LT", "15");
|
||||
conditionList.add(condition);
|
||||
|
||||
Condition condition1 = new Condition("orderStatus", "EQ", "READY");
|
||||
conditionList.add(condition1);
|
||||
|
||||
ArrayNode filteredData = filterDataService.filterData(items, conditionList);
|
||||
|
||||
assertEquals(filteredData.size(), 1);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterInConditionForStrings() {
|
||||
String data = "[\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2381224,\n" +
|
||||
" \"email\": \"michael.lawson@reqres.in\",\n" +
|
||||
" \"userName\": \"Michael Lawson\",\n" +
|
||||
" \"productName\": \"Chicken Sandwich\",\n" +
|
||||
" \"orderAmount\": 4.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2736212,\n" +
|
||||
" \"email\": \"lindsay.ferguson@reqres.in\",\n" +
|
||||
" \"userName\": \"Lindsay Ferguson\",\n" +
|
||||
" \"productName\": \"Tuna Salad\",\n" +
|
||||
" \"orderAmount\": 9.99,\n" +
|
||||
" \"orderStatus\": \"NOT READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 6788734,\n" +
|
||||
" \"email\": \"tobias.funke@reqres.in\",\n" +
|
||||
" \"userName\": \"Tobias Funke\",\n" +
|
||||
" \"productName\": \"Beef steak\",\n" +
|
||||
" \"orderAmount\": 19.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
try {
|
||||
ArrayNode items = (ArrayNode) objectMapper.readTree(data);
|
||||
|
||||
List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
Condition condition = new Condition("orderAmount", "LT", "15");
|
||||
conditionList.add(condition);
|
||||
|
||||
Condition condition1 = new Condition("orderStatus", "IN", "[\"READY\", \"NOT READY\"]");
|
||||
conditionList.add(condition1);
|
||||
|
||||
ArrayNode filteredData = filterDataService.filterData(items, conditionList);
|
||||
|
||||
assertEquals(filteredData.size(), 2);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterInConditionForNumbers() {
|
||||
String data = "[\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2381224,\n" +
|
||||
" \"email\": \"michael.lawson@reqres.in\",\n" +
|
||||
" \"userName\": \"Michael Lawson\",\n" +
|
||||
" \"productName\": \"Chicken Sandwich\",\n" +
|
||||
" \"orderAmount\": 4.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2736212,\n" +
|
||||
" \"email\": \"lindsay.ferguson@reqres.in\",\n" +
|
||||
" \"userName\": \"Lindsay Ferguson\",\n" +
|
||||
" \"productName\": \"Tuna Salad\",\n" +
|
||||
" \"orderAmount\": 9.99,\n" +
|
||||
" \"orderStatus\": \"NOT READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 6788734,\n" +
|
||||
" \"email\": \"tobias.funke@reqres.in\",\n" +
|
||||
" \"userName\": \"Tobias Funke\",\n" +
|
||||
" \"productName\": \"Beef steak\",\n" +
|
||||
" \"orderAmount\": 19.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
try {
|
||||
ArrayNode items = (ArrayNode) objectMapper.readTree(data);
|
||||
|
||||
List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
Condition condition = new Condition("orderAmount", "LT", "15");
|
||||
conditionList.add(condition);
|
||||
|
||||
Condition condition1 = new Condition("orderAmount", "IN", "[4.99, 19.99]");
|
||||
conditionList.add(condition1);
|
||||
|
||||
ArrayNode filteredData = filterDataService.filterData(items, conditionList);
|
||||
|
||||
assertEquals(filteredData.size(), 1);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterNotInConditionForNumbers() {
|
||||
String data = "[\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2381224,\n" +
|
||||
" \"email\": \"michael.lawson@reqres.in\",\n" +
|
||||
" \"userName\": \"Michael Lawson\",\n" +
|
||||
" \"productName\": \"Chicken Sandwich\",\n" +
|
||||
" \"orderAmount\": 4.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 2736212,\n" +
|
||||
" \"email\": \"lindsay.ferguson@reqres.in\",\n" +
|
||||
" \"userName\": \"Lindsay Ferguson\",\n" +
|
||||
" \"productName\": \"Tuna Salad\",\n" +
|
||||
" \"orderAmount\": 9.99,\n" +
|
||||
" \"orderStatus\": \"NOT READY\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"id\": 6788734,\n" +
|
||||
" \"email\": \"tobias.funke@reqres.in\",\n" +
|
||||
" \"userName\": \"Tobias Funke\",\n" +
|
||||
" \"productName\": \"Beef steak\",\n" +
|
||||
" \"orderAmount\": 19.99,\n" +
|
||||
" \"orderStatus\": \"READY\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
try {
|
||||
ArrayNode items = (ArrayNode) objectMapper.readTree(data);
|
||||
|
||||
List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
Condition condition = new Condition("orderAmount", "LT", "15");
|
||||
conditionList.add(condition);
|
||||
|
||||
Condition condition1 = new Condition("orderAmount", "NOT_IN", "[5.99, 19.00]");
|
||||
conditionList.add(condition1);
|
||||
|
||||
ArrayNode filteredData = filterDataService.filterData(items, conditionList);
|
||||
|
||||
assertEquals(filteredData.size(), 2);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ package com.external.utils;
|
|||
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
|
||||
import com.external.plugins.Op;
|
||||
import com.appsmith.external.constants.ConditionalOperator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.cloud.firestore.FieldPath;
|
||||
import com.google.cloud.firestore.Query;
|
||||
|
|
@ -26,9 +26,9 @@ public class WhereConditionUtils {
|
|||
);
|
||||
}
|
||||
|
||||
Op operator;
|
||||
ConditionalOperator operator;
|
||||
try {
|
||||
operator = StringUtils.isEmpty(operatorString) ? null : Op.valueOf(operatorString);
|
||||
operator = StringUtils.isEmpty(operatorString) ? null : ConditionalOperator.valueOf(operatorString);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AppsmithPluginException(
|
||||
AppsmithPluginError.PLUGIN_ERROR,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user