fix: Added handling for empty evaluated values (#19438)

This commit is contained in:
Nidhi 2023-01-04 02:17:57 +05:30 committed by GitHub
parent 71e0b3f2b3
commit 02c5c45972
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1470 additions and 1436 deletions

View File

@ -219,7 +219,7 @@ const mySqlData = {
["a", "abcdefghijklmnopqrst", "12345678912345", "true", "null"], ["a", "abcdefghijklmnopqrst", "12345678912345", "true", "null"],
["a", "abcdefghij", "012345", "false", "NulL"], ["a", "abcdefghij", "012345", "false", "NulL"],
["a", "b", "c"], ["a", "b", "c"],
["0", "1"], ["false", "true"],
[{"abc": "123"}, {}, [1, 2, 3, 4], [], ["a",true,0,12.34]], [{"abc": "123"}, {}, [1, 2, 3, 4], [], ["a",true,0,12.34]],
], ],
query: { query: {

View File

@ -46,9 +46,9 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>dev.miku</groupId> <groupId>org.mariadb</groupId>
<artifactId>r2dbc-mysql</artifactId> <artifactId>r2dbc-mariadb</artifactId>
<version>0.8.2.RELEASE</version> <version>1.1.3</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>

View File

@ -37,6 +37,7 @@ import io.r2dbc.spi.Statement;
import io.r2dbc.spi.ValidationDepth; import io.r2dbc.spi.ValidationDepth;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.ObjectUtils;
import org.mariadb.r2dbc.MariadbConnectionFactoryProvider;
import org.pf4j.Extension; import org.pf4j.Extension;
import org.pf4j.PluginWrapper; import org.pf4j.PluginWrapper;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@ -298,7 +299,7 @@ public class MySqlPlugin extends BasePlugin {
resultMono = resultFlux resultMono = resultFlux
.flatMap(Result::getRowsUpdated) .flatMap(Result::getRowsUpdated)
.collectList() .collectList()
.flatMap(list -> Mono.just(list.get(list.size() - 1))) .map(list -> list.get(list.size() - 1))
.map(rowsUpdated -> { .map(rowsUpdated -> {
rowsList.add( rowsList.add(
Map.of( Map.of(
@ -404,7 +405,7 @@ public class MySqlPlugin extends BasePlugin {
switch (appsmithType.type()) { switch (appsmithType.type()) {
case NULL: case NULL:
try { try {
connectionStatement.bindNull((index - 1), Object.class); connectionStatement.bindNull((index - 1), String.class);
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
// Do nothing. Move on // Do nothing. Move on
} }
@ -521,7 +522,7 @@ public class MySqlPlugin extends BasePlugin {
urlBuilder.append(String.join(",", hosts)).append("/"); urlBuilder.append(String.join(",", hosts)).append("/");
if (!StringUtils.isEmpty(authentication.getDatabaseName())) { if (StringUtils.hasLength(authentication.getDatabaseName())) {
urlBuilder.append(authentication.getDatabaseName()); urlBuilder.append(authentication.getDatabaseName());
} }
@ -542,6 +543,8 @@ public class MySqlPlugin extends BasePlugin {
ConnectionFactoryOptions baseOptions = ConnectionFactoryOptions.parse(urlBuilder.toString()); ConnectionFactoryOptions baseOptions = ConnectionFactoryOptions.parse(urlBuilder.toString());
ConnectionFactoryOptions.Builder ob = ConnectionFactoryOptions.builder().from(baseOptions) ConnectionFactoryOptions.Builder ob = ConnectionFactoryOptions.builder().from(baseOptions)
.option(ConnectionFactoryOptions.DRIVER, MariadbConnectionFactoryProvider.MARIADB_DRIVER)
.option(MariadbConnectionFactoryProvider.ALLOW_MULTI_QUERIES, true)
.option(ConnectionFactoryOptions.USER, authentication.getUsername()) .option(ConnectionFactoryOptions.USER, authentication.getUsername())
.option(ConnectionFactoryOptions.PASSWORD, authentication.getPassword()); .option(ConnectionFactoryOptions.PASSWORD, authentication.getPassword());

View File

@ -3,6 +3,7 @@ package com.appsmith.server.helpers;
import com.appsmith.external.constants.AnalyticsEvents; import com.appsmith.external.constants.AnalyticsEvents;
import com.appsmith.external.git.FileInterface; import com.appsmith.external.git.FileInterface;
import com.appsmith.external.helpers.Stopwatch; import com.appsmith.external.helpers.Stopwatch;
import com.appsmith.external.models.ActionDTO;
import com.appsmith.external.models.ApplicationGitReference; import com.appsmith.external.models.ApplicationGitReference;
import com.appsmith.external.models.Datasource; import com.appsmith.external.models.Datasource;
import com.appsmith.git.helpers.FileUtilsImpl; import com.appsmith.git.helpers.FileUtilsImpl;
@ -14,7 +15,6 @@ import com.appsmith.server.domains.NewAction;
import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.Theme; import com.appsmith.server.domains.Theme;
import com.appsmith.server.dtos.ActionCollectionDTO; import com.appsmith.server.dtos.ActionCollectionDTO;
import com.appsmith.external.models.ActionDTO;
import com.appsmith.server.dtos.ApplicationJson; import com.appsmith.server.dtos.ApplicationJson;
import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.dtos.PageDTO;
import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithError;
@ -64,15 +64,19 @@ public class GitFileUtils {
private final AnalyticsService analyticsService; private final AnalyticsService analyticsService;
private final SessionUserService sessionUserService; private final SessionUserService sessionUserService;
private final Gson gson;
// Only include the application helper fields in metadata object // Only include the application helper fields in metadata object
private static final Set<String> blockedMetadataFields private static final Set<String> blockedMetadataFields
= Set.of(EXPORTED_APPLICATION, DATASOURCE_LIST, PAGE_LIST, ACTION_LIST, ACTION_COLLECTION_LIST, DECRYPTED_FIELDS, EDIT_MODE_THEME); = Set.of(EXPORTED_APPLICATION, DATASOURCE_LIST, PAGE_LIST, ACTION_LIST, ACTION_COLLECTION_LIST, DECRYPTED_FIELDS, EDIT_MODE_THEME);
/** /**
* This method will save the complete application in the local repo directory. * This method will save the complete application in the local repo directory.
* Path to repo will be : ./container-volumes/git-repo/workspaceId/defaultApplicationId/repoName/{application_data} * Path to repo will be : ./container-volumes/git-repo/workspaceId/defaultApplicationId/repoName/{application_data}
* @param baseRepoSuffix path suffix used to create a local repo path *
* @param baseRepoSuffix path suffix used to create a local repo path
* @param applicationJson application reference object from which entire application can be rehydrated * @param applicationJson application reference object from which entire application can be rehydrated
* @param branchName name of the branch for the current application * @param branchName name of the branch for the current application
* @return repo path where the application is stored * @return repo path where the application is stored
*/ */
public Mono<Path> saveApplicationToLocalRepo(Path baseRepoSuffix, public Mono<Path> saveApplicationToLocalRepo(Path baseRepoSuffix,
@ -112,8 +116,9 @@ public class GitFileUtils {
/** /**
* Method to convert application resources to the structure which can be serialised by appsmith-git module for * Method to convert application resources to the structure which can be serialised by appsmith-git module for
* serialisation * serialisation
*
* @param applicationJson application resource including actions, jsobjects, pages * @param applicationJson application resource including actions, jsobjects, pages
* @return resource which can be saved to file system * @return resource which can be saved to file system
*/ */
public ApplicationGitReference createApplicationReference(ApplicationJson applicationJson) { public ApplicationGitReference createApplicationReference(ApplicationJson applicationJson) {
ApplicationGitReference applicationReference = new ApplicationGitReference(); ApplicationGitReference applicationReference = new ApplicationGitReference();
@ -221,9 +226,9 @@ public class GitFileUtils {
/** /**
* Method to reconstruct the application from the local git repo * Method to reconstruct the application from the local git repo
* *
* @param workspaceId To which workspace application needs to be rehydrated * @param workspaceId To which workspace application needs to be rehydrated
* @param defaultApplicationId Root application for the current branched application * @param defaultApplicationId Root application for the current branched application
* @param branchName for which branch the application needs to rehydrate * @param branchName for which branch the application needs to rehydrate
* @return application reference from which entire application can be rehydrated * @return application reference from which entire application can be rehydrated
*/ */
public Mono<ApplicationJson> reconstructApplicationJsonFromGitRepo(String workspaceId, public Mono<ApplicationJson> reconstructApplicationJsonFromGitRepo(String workspaceId,
@ -267,7 +272,6 @@ public class GitFileUtils {
if (resource == null) { if (resource == null) {
return null; return null;
} }
Gson gson = new Gson();
return gson.fromJson(gson.toJson(resource), type); return gson.fromJson(gson.toJson(resource), type);
} }
@ -286,12 +290,13 @@ public class GitFileUtils {
public Mono<Path> initializeReadme(Path baseRepoSuffix, public Mono<Path> initializeReadme(Path baseRepoSuffix,
String viewModeUrl, String viewModeUrl,
String editModeUrl) throws IOException { String editModeUrl) throws IOException {
return fileUtils.initializeReadme(baseRepoSuffix,viewModeUrl, editModeUrl) return fileUtils.initializeReadme(baseRepoSuffix, viewModeUrl, editModeUrl)
.onErrorResume(e -> Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e))); .onErrorResume(e -> Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e)));
} }
/** /**
* When the user clicks on detach remote, we need to remove the repo from the file system * When the user clicks on detach remote, we need to remove the repo from the file system
*
* @param baseRepoSuffix path suffix used to create a branch repo path as per worktree implementation * @param baseRepoSuffix path suffix used to create a branch repo path as per worktree implementation
* @return success on remove of file system * @return success on remove of file system
*/ */
@ -339,7 +344,6 @@ public class GitFileUtils {
// Clone the edit mode theme to published theme as both should be same for git connected application because we // Clone the edit mode theme to published theme as both should be same for git connected application because we
// do deploy and push as a single operation // do deploy and push as a single operation
applicationJson.setPublishedTheme(applicationJson.getEditModeTheme()); applicationJson.setPublishedTheme(applicationJson.getEditModeTheme());
Gson gson = new Gson();
if (application != null && !CollectionUtils.isNullOrEmpty(application.getPages())) { if (application != null && !CollectionUtils.isNullOrEmpty(application.getPages())) {
// Remove null values // Remove null values

View File

@ -641,7 +641,7 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
for (Param param : params) { for (Param param : params) {
// In case the parameter values turn out to be null, set it to empty string instead to allow // In case the parameter values turn out to be null, set it to empty string instead to allow
// the execution to go through no matter what. // the execution to go through no matter what.
if (!StringUtils.isEmpty(param.getKey()) && param.getValue() == null) { if (StringUtils.hasLength(param.getKey()) && param.getValue() == null) {
param.setValue(""); param.setValue("");
} }
} }
@ -1083,6 +1083,8 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
if (dto.getActionId() == null) { if (dto.getActionId() == null) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ACTION_ID)); return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ACTION_ID));
} }
final Set<String> visitedBindings = new HashSet<>();
/* /*
Parts in multipart request can appear in any order. In order to avoid NPE original name of the parameters Parts in multipart request can appear in any order. In order to avoid NPE original name of the parameters
along with the client-side data type are set here as it's guaranteed at this point that the part having the parameterMap is already collected. along with the client-side data type are set here as it's guaranteed at this point that the part having the parameterMap is already collected.
@ -1091,8 +1093,9 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
params.forEach( params.forEach(
param -> { param -> {
String pseudoBindingName = param.getPseudoBindingName(); String pseudoBindingName = param.getPseudoBindingName();
param.setKey(dto.getInvertParameterMap() String bindingValue = dto.getInvertParameterMap().get(pseudoBindingName);
.get(pseudoBindingName)); param.setKey(bindingValue);
visitedBindings.add(bindingValue);
//if the type is not an array e.g. "k1": "string" or "k1": "boolean" //if the type is not an array e.g. "k1": "string" or "k1": "boolean"
if (dto.getParamProperties() if (dto.getParamProperties()
.get(pseudoBindingName) instanceof String) { .get(pseudoBindingName) instanceof String) {
@ -1123,6 +1126,20 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
} }
); );
// In case there are parameters that did not receive a value in the multipart request,
// initialize these bindings with empty strings
if (dto.getParameterMap() != null) {
dto.getParameterMap()
.keySet()
.stream()
.forEach(parameter -> {
if (!visitedBindings.contains(parameter)) {
Param newParam = new Param(parameter, "");
params.add(newParam);
}
});
}
dto.setParams(params); dto.setParams(params);
return Mono.just(dto); return Mono.just(dto);
}); });