Adding the database changelog for Redis (#1346)

1. Fixing the build by excluding the slf4j-api from redis-plugin pom.xml
2. Adding the editor.json and form.json for the query pane & datasource pane.
3. Adding array handling in the Redis response by feeding all the output into a "result" key
This commit is contained in:
Arpit Mohan 2020-10-22 16:40:19 +05:30 committed by GitHub
parent bf69c7d66b
commit 74fe08f8bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 153 additions and 17 deletions

View File

@ -49,13 +49,20 @@
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
@ -74,7 +81,7 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.14.1</version>
<version>1.15.0-rc2</version>
<scope>test</scope>
</dependency>
@ -109,6 +116,23 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@ -1,6 +1,11 @@
package com.external.plugins;
import com.appsmith.external.models.*;
import com.appsmith.external.models.ActionConfiguration;
import com.appsmith.external.models.ActionExecutionResult;
import com.appsmith.external.models.AuthenticationDTO;
import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.DatasourceTestResult;
import com.appsmith.external.models.Endpoint;
import com.appsmith.external.pluginExceptions.AppsmithPluginError;
import com.appsmith.external.pluginExceptions.AppsmithPluginException;
import com.appsmith.external.plugins.BasePlugin;
@ -19,7 +24,10 @@ import redis.clients.jedis.util.SafeEncoder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class RedisPlugin extends BasePlugin {
private static final Integer DEFAULT_PORT = 6379;
@ -61,19 +69,25 @@ public class RedisPlugin extends BasePlugin {
}
ActionExecutionResult actionExecutionResult = new ActionExecutionResult();
actionExecutionResult.setBody(processCommandOutput(commandOutput));
actionExecutionResult.setBody(objectMapper.valueToTree(processCommandOutput(commandOutput)));
actionExecutionResult.setIsExecutionSuccess(true);
return Mono.just(actionExecutionResult);
}
// This will be updated as we encounter different outputs.
private String processCommandOutput(Object commandOutput) {
private List<Map<String, String>> processCommandOutput(Object commandOutput) {
if (commandOutput == null) {
return "null";
return List.of(Map.of("result", "null"));
} else if (commandOutput instanceof byte[]) {
return SafeEncoder.encode((byte[]) commandOutput);
return List.of(Map.of("result", SafeEncoder.encode((byte[]) commandOutput)));
} else if (commandOutput instanceof List) {
List<byte[]> commandList = (List<byte[]>) commandOutput;
return commandList.stream()
.map(obj -> Map.of("result", SafeEncoder.encode(obj)))
.collect(Collectors.toList());
} else {
return String.valueOf(commandOutput);
return List.of(Map.of("result", String.valueOf(commandOutput)));
}
}
@ -151,13 +165,13 @@ public class RedisPlugin extends BasePlugin {
@Override
public Mono<DatasourceTestResult> testDatasource(DatasourceConfiguration datasourceConfiguration) {
return datasourceCreate(datasourceConfiguration).
map(jedis -> {
return datasourceCreate(datasourceConfiguration)
.map(jedis -> {
verifyPing(jedis).block();
datasourceDestroy(jedis);
return new DatasourceTestResult();
}).
onErrorResume(error -> Mono.just(new DatasourceTestResult(error.getMessage())));
})
.onErrorResume(error -> Mono.just(new DatasourceTestResult(error.getMessage())));
}
}

View File

@ -0,0 +1,15 @@
{
"editor": [
{
"sectionName": "",
"id": 1,
"children": [
{
"label": "",
"configProperty": "actionConfiguration.body",
"controlType": "QUERY_DYNAMIC_TEXT"
}
]
}
]
}

View File

@ -0,0 +1,52 @@
{
"form": [
{
"sectionName": "Connection",
"id": 1,
"children": [
{
"sectionName": null,
"children": [
{
"label": "Host Address",
"configProperty": "datasourceConfiguration.endpoints[*].host",
"controlType": "KEYVALUE_ARRAY",
"validationMessage": "Please enter a valid host",
"validationRegex": "^((?![/:]).)*$"
},
{
"label": "Port",
"configProperty": "datasourceConfiguration.endpoints[*].port",
"dataType": "NUMBER",
"controlType": "KEYVALUE_ARRAY"
}
]
}
]
},
{
"sectionName": "Authentication",
"id": 2,
"children": [
{
"sectionName": null,
"children": [
{
"label": "Username",
"configProperty": "datasourceConfiguration.authentication.username",
"controlType": "INPUT_TEXT",
"placeholderText": "Username"
},
{
"label": "Password",
"configProperty": "datasourceConfiguration.authentication.password",
"dataType": "PASSWORD",
"controlType": "INPUT_TEXT",
"placeholderText": "Password"
}
]
}
]
}
]
}

View File

@ -1,7 +1,14 @@
package com.external.plugins;
import com.appsmith.external.models.*;
import com.appsmith.external.models.ActionConfiguration;
import com.appsmith.external.models.ActionExecutionResult;
import com.appsmith.external.models.AuthenticationDTO;
import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.DatasourceTestResult;
import com.appsmith.external.models.Endpoint;
import com.appsmith.external.pluginExceptions.AppsmithPluginException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.BeforeClass;
@ -166,7 +173,8 @@ public class RedisPluginTest {
.assertNext(actionExecutionResult -> {
Assert.assertNotNull(actionExecutionResult);
Assert.assertNotNull(actionExecutionResult.getBody());
Assert.assertEquals(actionExecutionResult.getBody(), "PONG");
final JsonNode node = ((ArrayNode) actionExecutionResult.getBody()).get(0);
Assert.assertEquals(node.get("result").asText(), "PONG");
}).verifyComplete();
}
@ -184,7 +192,8 @@ public class RedisPluginTest {
.assertNext(actionExecutionResult -> {
Assert.assertNotNull(actionExecutionResult);
Assert.assertNotNull(actionExecutionResult.getBody());
Assert.assertEquals(actionExecutionResult.getBody(), "null");
final JsonNode node = ((ArrayNode) actionExecutionResult.getBody()).get(0);
Assert.assertEquals(node.get("result").asText(), "null");
}).verifyComplete();
// Setting a key
@ -196,7 +205,8 @@ public class RedisPluginTest {
.assertNext(actionExecutionResult -> {
Assert.assertNotNull(actionExecutionResult);
Assert.assertNotNull(actionExecutionResult.getBody());
Assert.assertEquals(actionExecutionResult.getBody(), "OK");
final JsonNode node = ((ArrayNode) actionExecutionResult.getBody()).get(0);
Assert.assertEquals(node.get("result").asText(), "OK");
}).verifyComplete();
// Getting the key
@ -206,7 +216,8 @@ public class RedisPluginTest {
.assertNext(actionExecutionResult -> {
Assert.assertNotNull(actionExecutionResult);
Assert.assertNotNull(actionExecutionResult.getBody());
Assert.assertEquals(actionExecutionResult.getBody(), "value");
final JsonNode node = ((ArrayNode) actionExecutionResult.getBody()).get(0);
Assert.assertEquals(node.get("result").asText(), "value");
}).verifyComplete();
}
}

View File

@ -974,6 +974,26 @@ public class DatabaseChangelog {
);
}
@ChangeSet(order = "030", id = "add-redis-plugin", author = "")
public void addRedisPlugin(MongoTemplate mongoTemplate) {
Plugin plugin1 = new Plugin();
plugin1.setName("Redis");
plugin1.setType(PluginType.DB);
plugin1.setPackageName("redis-plugin");
plugin1.setUiComponent("DbEditorForm");
plugin1.setResponseType(Plugin.ResponseType.TABLE);
plugin1.setIconLocation("https://s3.us-east-2.amazonaws.com/assets.appsmith.com/redis.jpg");
plugin1.setDocumentationLink("https://docs.appsmith.com/core-concepts/connecting-to-databases/querying-redis");
plugin1.setDefaultInstall(true);
try {
mongoTemplate.insert(plugin1);
} catch (DuplicateKeyException e) {
log.warn(plugin1.getPackageName() + " already present in database.");
}
installPluginToAllOrganizations(mongoTemplate, plugin1.getId());
}
private void installPluginToAllOrganizations(MongoTemplate mongoTemplate, String pluginId) {
for (Organization organization : mongoTemplate.findAll(Organization.class)) {
if (CollectionUtils.isEmpty(organization.getPlugins())) {