fix: fix Arangodb plugin response on update commands (#7182)

* ArangoDB has two types of command - one that fetches a response and the other that updates a document. Currently, ArangoDB plugin treats all cmds like the one that returns a response, hence when update cmds are run then an empty response is returned to the client since there is nothing to fetch. This PR adds a check to fetch the response based on the type of cmd. Hence, for an update cmd the number of writes succeeded or failed would be returned as a response.
This commit is contained in:
Sumit Kumar 2021-09-07 09:38:23 +05:30 committed by GitHub
parent 1d2bcb277b
commit 77a33f770d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 10 deletions

View File

@ -34,6 +34,7 @@ import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@ -52,6 +53,20 @@ import static com.external.utils.StructureUtils.getOneDocumentQuery;
public class ArangoDBPlugin extends BasePlugin {
private static long DEFAULT_PORT = 8529L;
private static String WRITES_EXECUTED_KEY = "writesExecuted";
private static String WRITES_IGNORED_KEY = "writesIgnored";
private static String RETURN_KEY = "return";
/**
* - Regex to match everything inside double or single quotes, including the quotes.
* - e.g. Earth "revolves'" '"around"' "the" 'sun' will match:
* (1) "revolves'"
* (2) '"around"'
* (3) "the"
* (4) 'sun'
* - ref: https://stackoverflow.com/questions/171480/regex-grabbing-values-between-quotation-marks
*/
private static String MATCH_QUOTED_WORDS_REGEX = "([\\\"'])(?:(?=(\\\\?))\\2.)*?\\1";
public ArangoDBPlugin(PluginWrapper wrapper) {
super(wrapper);
@ -85,13 +100,24 @@ public class ArangoDBPlugin extends BasePlugin {
}
return Mono.fromCallable(() -> {
ArangoCursor<Map> cursor = db.query(query, null, null, Map.class);
List<Map> docList = new ArrayList<>();
docList.addAll(cursor.asListRemaining());
ActionExecutionResult result = new ActionExecutionResult();
result.setBody(objectMapper.valueToTree(docList));
result.setIsExecutionSuccess(true);
System.out.println(Thread.currentThread().getName() + ": In the ArangoDBPlugin, got action execution result");
ArangoCursor<Map> cursor = db.query(query, null, null, Map.class);
ActionExecutionResult result = new ActionExecutionResult();
result.setIsExecutionSuccess(true);
List<Map> docList = new ArrayList<>();
if (isUpdateQuery(query)) {
Map<String, Long> updateCount = new HashMap<>();
updateCount.put(WRITES_EXECUTED_KEY, cursor.getStats().getWritesExecuted());
updateCount.put(WRITES_IGNORED_KEY, cursor.getStats().getWritesIgnored());
docList.add(updateCount);
}
else {
docList.addAll(cursor.asListRemaining());
}
result.setBody(objectMapper.valueToTree(docList));
return result;
})
.onErrorResume(error -> {
@ -111,6 +137,24 @@ public class ArangoDBPlugin extends BasePlugin {
.subscribeOn(scheduler);
}
/**
* - In ArangoDB query language, any non-update query is indicated by the use of keyword RETURN.
* - This method checks if the query provided by user has the RETURN keyword or not. To do so, it first
* removes any string present inside double or single quotes (to remove any usage of the keyword as a value).
* It then matches the remaining words with the keyword RETURN.
* - Quoting from ArangoDB doc:
* ```
* An AQL query must either return a result (indicated by usage of the RETURN keyword) or execute a
* data-modification operation
* ```
* ref: https://www.arangodb.com/docs/stable/aql/fundamentals-syntax.html
*/
private boolean isUpdateQuery(String query) {
String queryKeyWordsOnly = query.replaceAll(MATCH_QUOTED_WORDS_REGEX, "");
return !Arrays.stream(queryKeyWordsOnly.split("\\s"))
.anyMatch(word -> RETURN_KEY.equals(word.trim().toLowerCase()));
}
/**
* - ArangoDatabase object does not seem to provide any API to check if connection object is valid, hence
* adding only null check for now.

View File

@ -245,6 +245,7 @@ public class ArangoDBPluginTest {
" name: 'John Smith'," +
" email: ['john@appsmith.com](mailto:%22john@appsmith.com)']," +
" gender: 'M'," +
" testKeyWord: ' Return '," +
" age: 50" +
" } INTO users");
Mono<Object> executeMono = dsConnectionMono.flatMap(conn -> pluginExecutor.execute(conn, dsConfig, actionConfiguration));
@ -255,10 +256,10 @@ public class ArangoDBPluginTest {
assertNotNull(result);
assertTrue(result.getIsExecutionSuccess());
assertNotNull(result.getBody());
// On a successful update the server returns an empty array
assertEquals(0, ((ArrayNode) result.getBody()).size());
ArrayNode node = (ArrayNode) result.getBody();
assertEquals(1, node.size());
assertEquals(1, (node.get(0)).get("writesExecuted").asInt());
assertEquals(0, (node.get(0)).get("writesIgnored").asInt());
})
.verifyComplete();
}