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
|
||||
Boolean isMock;
|
||||
|
||||
@Transient
|
||||
Map<String, Object> metadata;
|
||||
|
||||
public DatasourceStorage(
|
||||
String datasourceId,
|
||||
String environmentId,
|
||||
|
|
|
|||
|
|
@ -185,6 +185,13 @@ public interface PluginExecutor<C> extends ExtensionPoint, CrudTemplateService {
|
|||
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
|
||||
* easier for the user.
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ public class FieldNameCE {
|
|||
|
||||
public static final String REMOTE_PLUGINS = "remotePlugins";
|
||||
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 VERSION = "version";
|
||||
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.NewActionRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.ConfigService;
|
||||
import com.appsmith.server.services.DatasourceContextService;
|
||||
import com.appsmith.server.services.FeatureFlagService;
|
||||
import com.appsmith.server.services.SequenceService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
import com.appsmith.server.services.TenantService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.appsmith.server.solutions.DatasourcePermission;
|
||||
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_PLUGINS_IN_WORKSPACE;
|
||||
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.helpers.CollectionUtils.isNullOrEmpty;
|
||||
import static com.appsmith.server.helpers.DatasourceAnalyticsUtils.getAnalyticsProperties;
|
||||
|
|
@ -93,6 +97,8 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
|||
private final RateLimitService rateLimitService;
|
||||
private final FeatureFlagService featureFlagService;
|
||||
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
|
||||
// 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,
|
||||
RateLimitService rateLimitService,
|
||||
FeatureFlagService featureFlagService,
|
||||
ObservationRegistry observationRegistry) {
|
||||
ObservationRegistry observationRegistry,
|
||||
TenantService tenantService,
|
||||
ConfigService configService) {
|
||||
|
||||
this.workspaceService = workspaceService;
|
||||
this.sessionUserService = sessionUserService;
|
||||
|
|
@ -138,6 +146,8 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
|||
this.rateLimitService = rateLimitService;
|
||||
this.featureFlagService = featureFlagService;
|
||||
this.observationRegistry = observationRegistry;
|
||||
this.tenantService = tenantService;
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -223,27 +233,28 @@ public class DatasourceServiceCEImpl implements DatasourceServiceCE {
|
|||
}
|
||||
|
||||
return datasourceMono.flatMap(savedDatasource -> this.organiseDatasourceStorages(savedDatasource)
|
||||
.flatMap(datasourceStorage -> {
|
||||
// Make sure that we are creating entries only if the id is not already populated
|
||||
if (hasText(datasourceStorage.getId())) {
|
||||
return Mono.just(datasourceStorage);
|
||||
}
|
||||
.flatMap(datasourceStorageX -> setAdditionalMetadataInDatasourceStorage(datasourceStorageX)
|
||||
.flatMap(datasourceStorage -> {
|
||||
// Make sure that we are creating entries only if the id is not already populated
|
||||
if (hasText(datasourceStorage.getId())) {
|
||||
return Mono.just(datasourceStorage);
|
||||
}
|
||||
|
||||
return datasourceStorageService
|
||||
.create(datasourceStorage, isDryOps)
|
||||
.map(datasourceStorage1 -> {
|
||||
if (datasourceStorageDryRunQueries != null && isDryOps) {
|
||||
List<DatasourceStorage> datasourceStorages =
|
||||
datasourceStorageDryRunQueries.get(SAVE);
|
||||
if (datasourceStorages == null) {
|
||||
datasourceStorages = new ArrayList<>();
|
||||
}
|
||||
datasourceStorages.add(datasourceStorage1);
|
||||
datasourceStorageDryRunQueries.put(SAVE, datasourceStorages);
|
||||
}
|
||||
return datasourceStorage1;
|
||||
});
|
||||
})
|
||||
return datasourceStorageService
|
||||
.create(datasourceStorage, isDryOps)
|
||||
.map(datasourceStorage1 -> {
|
||||
if (datasourceStorageDryRunQueries != null && isDryOps) {
|
||||
List<DatasourceStorage> datasourceStorages =
|
||||
datasourceStorageDryRunQueries.get(SAVE);
|
||||
if (datasourceStorages == null) {
|
||||
datasourceStorages = new ArrayList<>();
|
||||
}
|
||||
datasourceStorages.add(datasourceStorage1);
|
||||
datasourceStorageDryRunQueries.put(SAVE, datasourceStorages);
|
||||
}
|
||||
return datasourceStorage1;
|
||||
});
|
||||
}))
|
||||
.map(datasourceStorageService::createDatasourceStorageDTOFromDatasourceStorage)
|
||||
.collectMap(DatasourceStorageDTO::getEnvironmentId)
|
||||
.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
|
||||
protected Flux<DatasourceStorage> organiseDatasourceStorages(@NotNull Datasource savedDatasource) {
|
||||
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.NewActionRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.ConfigService;
|
||||
import com.appsmith.server.services.DatasourceContextService;
|
||||
import com.appsmith.server.services.FeatureFlagService;
|
||||
import com.appsmith.server.services.SequenceService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
import com.appsmith.server.services.TenantService;
|
||||
import com.appsmith.server.services.WorkspaceService;
|
||||
import com.appsmith.server.solutions.DatasourcePermission;
|
||||
import com.appsmith.server.solutions.EnvironmentPermission;
|
||||
|
|
@ -41,7 +43,9 @@ public class DatasourceServiceImpl extends DatasourceServiceCEImpl implements Da
|
|||
EnvironmentPermission environmentPermission,
|
||||
RateLimitService rateLimitService,
|
||||
FeatureFlagService featureFlagService,
|
||||
ObservationRegistry observationRegistry) {
|
||||
ObservationRegistry observationRegistry,
|
||||
TenantService tenantService,
|
||||
ConfigService configService) {
|
||||
|
||||
super(
|
||||
repository,
|
||||
|
|
@ -60,6 +64,8 @@ public class DatasourceServiceImpl extends DatasourceServiceCEImpl implements Da
|
|||
environmentPermission,
|
||||
rateLimitService,
|
||||
featureFlagService,
|
||||
observationRegistry);
|
||||
observationRegistry,
|
||||
tenantService,
|
||||
configService);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,6 +183,16 @@ public class DatasourceStorageServiceCEImpl implements DatasourceStorageServiceC
|
|||
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
|
||||
public Mono<DatasourceStorage> validateDatasourceStorage(DatasourceStorage datasourceStorage) {
|
||||
|
||||
|
|
@ -242,7 +252,10 @@ public class DatasourceStorageServiceCEImpl implements DatasourceStorageServiceC
|
|||
unsavedDatasourceStorage.updateForBulkWriteOperation();
|
||||
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