Skip to content

Commit

Permalink
chore: add postSaveHook (#39306)
Browse files Browse the repository at this point in the history
## 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: 260ad93
> <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 <[email protected]>
  • Loading branch information
nsarupr and nsarupr authored Feb 18, 2025
1 parent e4ed590 commit d921110
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public class DatasourceStorage extends GitSyncedDomain {
@Transient
Boolean isMock;

@Transient
Map<String, Object> metadata;

public DatasourceStorage(
String datasourceId,
String environmentId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ default Mono<DatasourceStorage> preDeleteHook(DatasourceStorage datasourceStorag
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
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;
Expand Down Expand Up @@ -64,6 +66,8 @@
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;
Expand Down Expand Up @@ -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
Expand All @@ -119,7 +125,9 @@ public DatasourceServiceCEImpl(
EnvironmentPermission environmentPermission,
RateLimitService rateLimitService,
FeatureFlagService featureFlagService,
ObservationRegistry observationRegistry) {
ObservationRegistry observationRegistry,
TenantService tenantService,
ConfigService configService) {

this.workspaceService = workspaceService;
this.sessionUserService = sessionUserService;
Expand All @@ -138,6 +146,8 @@ public DatasourceServiceCEImpl(
this.rateLimitService = rateLimitService;
this.featureFlagService = featureFlagService;
this.observationRegistry = observationRegistry;
this.tenantService = tenantService;
this.configService = configService;
}

@Override
Expand Down Expand Up @@ -223,27 +233,28 @@ private Mono<Datasource> createEx(
}

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 -> {
Expand All @@ -252,6 +263,20 @@ private Mono<Datasource> createEx(
}));
}

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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
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;
Expand Down Expand Up @@ -41,7 +43,9 @@ public DatasourceServiceImpl(
EnvironmentPermission environmentPermission,
RateLimitService rateLimitService,
FeatureFlagService featureFlagService,
ObservationRegistry observationRegistry) {
ObservationRegistry observationRegistry,
TenantService tenantService,
ConfigService configService) {

super(
repository,
Expand All @@ -60,6 +64,8 @@ public DatasourceServiceImpl(
environmentPermission,
rateLimitService,
featureFlagService,
observationRegistry);
observationRegistry,
tenantService,
configService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ public Mono<DatasourceStorage> executePreSaveActions(DatasourceStorage datasourc
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) {

Expand Down Expand Up @@ -242,7 +252,10 @@ private Mono<DatasourceStorage> validateAndSaveDatasourceStorageToRepository(
unsavedDatasourceStorage.updateForBulkWriteOperation();
return Mono.just(unsavedDatasourceStorage);
}
return repository.save(unsavedDatasourceStorage).thenReturn(unsavedDatasourceStorage);
return repository
.save(unsavedDatasourceStorage)
.then(this.executePostSaveActions(unsavedDatasourceStorage))
.thenReturn(unsavedDatasourceStorage);
});
}

Expand Down

0 comments on commit d921110

Please sign in to comment.