chore: add postSaveHook (#39306)
## Description > [!IMPORTANT] > Add a post save hook on datasources. Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Sanity" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/13386879786> > Commit: 260ad934fc1295d2ad5ed035ff593c9950158c74 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=13386879786&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Sanity` > Spec: > <hr>Tue, 18 Feb 2025 09:36:50 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Enhanced multi-tenant support: Datasource records now incorporate tenant and instance details for seamless management across environments. - Extended post-save actions: Datasource saving triggers additional operations via plugin integrations to improve overall functionality. - New transient metadata field added to DatasourceStorage for additional data handling. - New post-save hook method introduced for plugins to perform actions after saving a datasource. - New constant `TENANT_ID` added for consistent field name referencing. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Nilesh Sarupriya <20905988+nsarupr@users.noreply.github.com>
This commit is contained in:
parent
e4ed590822
commit
d921110658
|
|
@ -89,6 +89,9 @@ public class DatasourceStorage extends GitSyncedDomain {
|
||||||
@Transient
|
@Transient
|
||||||
Boolean isMock;
|
Boolean isMock;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
Map<String, Object> metadata;
|
||||||
|
|
||||||
public DatasourceStorage(
|
public DatasourceStorage(
|
||||||
String datasourceId,
|
String datasourceId,
|
||||||
String environmentId,
|
String environmentId,
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,13 @@ public interface PluginExecutor<C> extends ExtensionPoint, CrudTemplateService {
|
||||||
return Mono.just(datasourceStorage);
|
return Mono.just(datasourceStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is being called as a hook after saving a datasource.
|
||||||
|
*/
|
||||||
|
default Mono<DatasourceStorage> postSaveHook(DatasourceStorage datasourceStorage) {
|
||||||
|
return Mono.just(datasourceStorage);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function fetches the structure of the tables/collections in the datasource. It's used to make query creation
|
* This function fetches the structure of the tables/collections in the datasource. It's used to make query creation
|
||||||
* easier for the user.
|
* easier for the user.
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,7 @@ public class FieldNameCE {
|
||||||
|
|
||||||
public static final String REMOTE_PLUGINS = "remotePlugins";
|
public static final String REMOTE_PLUGINS = "remotePlugins";
|
||||||
public static final String INSTANCE_ID = "instanceId";
|
public static final String INSTANCE_ID = "instanceId";
|
||||||
|
public static final String TENANT_ID = "tenantId";
|
||||||
public static final String IP_ADDRESS = "ipAddress";
|
public static final String IP_ADDRESS = "ipAddress";
|
||||||
public static final String VERSION = "version";
|
public static final String VERSION = "version";
|
||||||
public static final String PUBLISHED = "published";
|
public static final String PUBLISHED = "published";
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,12 @@ import com.appsmith.server.ratelimiting.RateLimitService;
|
||||||
import com.appsmith.server.repositories.DatasourceRepository;
|
import com.appsmith.server.repositories.DatasourceRepository;
|
||||||
import com.appsmith.server.repositories.NewActionRepository;
|
import com.appsmith.server.repositories.NewActionRepository;
|
||||||
import com.appsmith.server.services.AnalyticsService;
|
import com.appsmith.server.services.AnalyticsService;
|
||||||
|
import com.appsmith.server.services.ConfigService;
|
||||||
import com.appsmith.server.services.DatasourceContextService;
|
import com.appsmith.server.services.DatasourceContextService;
|
||||||
import com.appsmith.server.services.FeatureFlagService;
|
import com.appsmith.server.services.FeatureFlagService;
|
||||||
import com.appsmith.server.services.SequenceService;
|
import com.appsmith.server.services.SequenceService;
|
||||||
import com.appsmith.server.services.SessionUserService;
|
import com.appsmith.server.services.SessionUserService;
|
||||||
|
import com.appsmith.server.services.TenantService;
|
||||||
import com.appsmith.server.services.WorkspaceService;
|
import com.appsmith.server.services.WorkspaceService;
|
||||||
import com.appsmith.server.solutions.DatasourcePermission;
|
import com.appsmith.server.solutions.DatasourcePermission;
|
||||||
import com.appsmith.server.solutions.EnvironmentPermission;
|
import com.appsmith.server.solutions.EnvironmentPermission;
|
||||||
|
|
@ -64,6 +66,8 @@ import java.util.UUID;
|
||||||
import static com.appsmith.external.constants.spans.DatasourceSpan.FETCH_ALL_DATASOURCES_WITH_STORAGES;
|
import static com.appsmith.external.constants.spans.DatasourceSpan.FETCH_ALL_DATASOURCES_WITH_STORAGES;
|
||||||
import static com.appsmith.external.constants.spans.DatasourceSpan.FETCH_ALL_PLUGINS_IN_WORKSPACE;
|
import static com.appsmith.external.constants.spans.DatasourceSpan.FETCH_ALL_PLUGINS_IN_WORKSPACE;
|
||||||
import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties;
|
import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties;
|
||||||
|
import static com.appsmith.server.constants.ce.FieldNameCE.INSTANCE_ID;
|
||||||
|
import static com.appsmith.server.constants.ce.FieldNameCE.TENANT_ID;
|
||||||
import static com.appsmith.server.dtos.DBOpsType.SAVE;
|
import static com.appsmith.server.dtos.DBOpsType.SAVE;
|
||||||
import static com.appsmith.server.helpers.CollectionUtils.isNullOrEmpty;
|
import static com.appsmith.server.helpers.CollectionUtils.isNullOrEmpty;
|
||||||
import static com.appsmith.server.helpers.DatasourceAnalyticsUtils.getAnalyticsProperties;
|
import static com.appsmith.server.helpers.DatasourceAnalyticsUtils.getAnalyticsProperties;
|
||||||
|
|
@ -93,6 +97,8 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
||||||
private final RateLimitService rateLimitService;
|
private final RateLimitService rateLimitService;
|
||||||
private final FeatureFlagService featureFlagService;
|
private final FeatureFlagService featureFlagService;
|
||||||
private final ObservationRegistry observationRegistry;
|
private final ObservationRegistry observationRegistry;
|
||||||
|
private final TenantService tenantService;
|
||||||
|
private final ConfigService configService;
|
||||||
|
|
||||||
// Defines blocking duration for test as well as connection created for query execution
|
// Defines blocking duration for test as well as connection created for query execution
|
||||||
// This will block the creation of datasource connection for 5 minutes, in case of more than 3 failed connection
|
// This will block the creation of datasource connection for 5 minutes, in case of more than 3 failed connection
|
||||||
|
|
@ -119,7 +125,9 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
||||||
EnvironmentPermission environmentPermission,
|
EnvironmentPermission environmentPermission,
|
||||||
RateLimitService rateLimitService,
|
RateLimitService rateLimitService,
|
||||||
FeatureFlagService featureFlagService,
|
FeatureFlagService featureFlagService,
|
||||||
ObservationRegistry observationRegistry) {
|
ObservationRegistry observationRegistry,
|
||||||
|
TenantService tenantService,
|
||||||
|
ConfigService configService) {
|
||||||
|
|
||||||
this.workspaceService = workspaceService;
|
this.workspaceService = workspaceService;
|
||||||
this.sessionUserService = sessionUserService;
|
this.sessionUserService = sessionUserService;
|
||||||
|
|
@ -138,6 +146,8 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
||||||
this.rateLimitService = rateLimitService;
|
this.rateLimitService = rateLimitService;
|
||||||
this.featureFlagService = featureFlagService;
|
this.featureFlagService = featureFlagService;
|
||||||
this.observationRegistry = observationRegistry;
|
this.observationRegistry = observationRegistry;
|
||||||
|
this.tenantService = tenantService;
|
||||||
|
this.configService = configService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -223,6 +233,7 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
||||||
}
|
}
|
||||||
|
|
||||||
return datasourceMono.flatMap(savedDatasource -> this.organiseDatasourceStorages(savedDatasource)
|
return datasourceMono.flatMap(savedDatasource -> this.organiseDatasourceStorages(savedDatasource)
|
||||||
|
.flatMap(datasourceStorageX -> setAdditionalMetadataInDatasourceStorage(datasourceStorageX)
|
||||||
.flatMap(datasourceStorage -> {
|
.flatMap(datasourceStorage -> {
|
||||||
// Make sure that we are creating entries only if the id is not already populated
|
// Make sure that we are creating entries only if the id is not already populated
|
||||||
if (hasText(datasourceStorage.getId())) {
|
if (hasText(datasourceStorage.getId())) {
|
||||||
|
|
@ -243,7 +254,7 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
||||||
}
|
}
|
||||||
return datasourceStorage1;
|
return datasourceStorage1;
|
||||||
});
|
});
|
||||||
})
|
}))
|
||||||
.map(datasourceStorageService::createDatasourceStorageDTOFromDatasourceStorage)
|
.map(datasourceStorageService::createDatasourceStorageDTOFromDatasourceStorage)
|
||||||
.collectMap(DatasourceStorageDTO::getEnvironmentId)
|
.collectMap(DatasourceStorageDTO::getEnvironmentId)
|
||||||
.map(savedStorages -> {
|
.map(savedStorages -> {
|
||||||
|
|
@ -252,6 +263,20 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Mono<DatasourceStorage> setAdditionalMetadataInDatasourceStorage(DatasourceStorage datasourceStorage) {
|
||||||
|
Mono<String> tenantIdMono = tenantService.getDefaultTenantId();
|
||||||
|
Mono<String> instanceIdMono = configService.getInstanceId();
|
||||||
|
|
||||||
|
Map<String, Object> metadata = new HashMap<>();
|
||||||
|
|
||||||
|
return tenantIdMono.zipWith(instanceIdMono).map(tuple -> {
|
||||||
|
metadata.put(TENANT_ID, tuple.getT1());
|
||||||
|
metadata.put(INSTANCE_ID, tuple.getT2());
|
||||||
|
datasourceStorage.setMetadata(metadata);
|
||||||
|
return datasourceStorage;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// this requires an EE override multiple environments
|
// this requires an EE override multiple environments
|
||||||
protected Flux<DatasourceStorage> organiseDatasourceStorages(@NotNull Datasource savedDatasource) {
|
protected Flux<DatasourceStorage> organiseDatasourceStorages(@NotNull Datasource savedDatasource) {
|
||||||
Map<String, DatasourceStorageDTO> storages = savedDatasource.getDatasourceStorages();
|
Map<String, DatasourceStorageDTO> storages = savedDatasource.getDatasourceStorages();
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,12 @@ import com.appsmith.server.ratelimiting.RateLimitService;
|
||||||
import com.appsmith.server.repositories.DatasourceRepository;
|
import com.appsmith.server.repositories.DatasourceRepository;
|
||||||
import com.appsmith.server.repositories.NewActionRepository;
|
import com.appsmith.server.repositories.NewActionRepository;
|
||||||
import com.appsmith.server.services.AnalyticsService;
|
import com.appsmith.server.services.AnalyticsService;
|
||||||
|
import com.appsmith.server.services.ConfigService;
|
||||||
import com.appsmith.server.services.DatasourceContextService;
|
import com.appsmith.server.services.DatasourceContextService;
|
||||||
import com.appsmith.server.services.FeatureFlagService;
|
import com.appsmith.server.services.FeatureFlagService;
|
||||||
import com.appsmith.server.services.SequenceService;
|
import com.appsmith.server.services.SequenceService;
|
||||||
import com.appsmith.server.services.SessionUserService;
|
import com.appsmith.server.services.SessionUserService;
|
||||||
|
import com.appsmith.server.services.TenantService;
|
||||||
import com.appsmith.server.services.WorkspaceService;
|
import com.appsmith.server.services.WorkspaceService;
|
||||||
import com.appsmith.server.solutions.DatasourcePermission;
|
import com.appsmith.server.solutions.DatasourcePermission;
|
||||||
import com.appsmith.server.solutions.EnvironmentPermission;
|
import com.appsmith.server.solutions.EnvironmentPermission;
|
||||||
|
|
@ -41,7 +43,9 @@ public class DatasourceServiceImpl extends DatasourceServiceCEImpl implements Da
|
||||||
EnvironmentPermission environmentPermission,
|
EnvironmentPermission environmentPermission,
|
||||||
RateLimitService rateLimitService,
|
RateLimitService rateLimitService,
|
||||||
FeatureFlagService featureFlagService,
|
FeatureFlagService featureFlagService,
|
||||||
ObservationRegistry observationRegistry) {
|
ObservationRegistry observationRegistry,
|
||||||
|
TenantService tenantService,
|
||||||
|
ConfigService configService) {
|
||||||
|
|
||||||
super(
|
super(
|
||||||
repository,
|
repository,
|
||||||
|
|
@ -60,6 +64,8 @@ public class DatasourceServiceImpl extends DatasourceServiceCEImpl implements Da
|
||||||
environmentPermission,
|
environmentPermission,
|
||||||
rateLimitService,
|
rateLimitService,
|
||||||
featureFlagService,
|
featureFlagService,
|
||||||
observationRegistry);
|
observationRegistry,
|
||||||
|
tenantService,
|
||||||
|
configService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,16 @@ public class DatasourceStorageServiceCEImpl implements DatasourceStorageServiceC
|
||||||
return pluginExecutorMono.flatMap(pluginExecutor -> pluginExecutor.preSaveHook(datasourceStorage));
|
return pluginExecutorMono.flatMap(pluginExecutor -> pluginExecutor.preSaveHook(datasourceStorage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Mono<DatasourceStorage> executePostSaveActions(DatasourceStorage datasourceStorage) {
|
||||||
|
Mono<Plugin> pluginMono = pluginService.findById(datasourceStorage.getPluginId());
|
||||||
|
Mono<PluginExecutor> pluginExecutorMono = pluginExecutorHelper
|
||||||
|
.getPluginExecutor(pluginMono)
|
||||||
|
.switchIfEmpty(Mono.error(new AppsmithException(
|
||||||
|
AppsmithError.NO_RESOURCE_FOUND, FieldName.PLUGIN, datasourceStorage.getPluginId())));
|
||||||
|
|
||||||
|
return pluginExecutorMono.flatMap(pluginExecutor -> pluginExecutor.postSaveHook(datasourceStorage));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<DatasourceStorage> validateDatasourceStorage(DatasourceStorage datasourceStorage) {
|
public Mono<DatasourceStorage> validateDatasourceStorage(DatasourceStorage datasourceStorage) {
|
||||||
|
|
||||||
|
|
@ -242,7 +252,10 @@ public class DatasourceStorageServiceCEImpl implements DatasourceStorageServiceC
|
||||||
unsavedDatasourceStorage.updateForBulkWriteOperation();
|
unsavedDatasourceStorage.updateForBulkWriteOperation();
|
||||||
return Mono.just(unsavedDatasourceStorage);
|
return Mono.just(unsavedDatasourceStorage);
|
||||||
}
|
}
|
||||||
return repository.save(unsavedDatasourceStorage).thenReturn(unsavedDatasourceStorage);
|
return repository
|
||||||
|
.save(unsavedDatasourceStorage)
|
||||||
|
.then(this.executePostSaveActions(unsavedDatasourceStorage))
|
||||||
|
.thenReturn(unsavedDatasourceStorage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user