From 7037d99cfa109140d244eecff5c048e5bd03735b Mon Sep 17 00:00:00 2001 From: Shrikant Kandula Date: Wed, 20 May 2020 11:21:32 +0000 Subject: [PATCH] Use sequences for numbering new datasources. --- .../appsmith/server/domains/Datasource.java | 4 ++ .../com/appsmith/server/domains/Sequence.java | 12 +++++ .../server/migrations/DatabaseChangelog.java | 39 +++++++++++++-- .../repositories/DatasourceRepository.java | 4 -- .../server/services/DatasourceService.java | 3 +- .../services/DatasourceServiceImpl.java | 22 ++++----- .../server/services/SequenceService.java | 14 ++++++ .../server/services/SequenceServiceImpl.java | 48 +++++++++++++++++++ .../services/DatasourceServiceTest.java | 4 +- 9 files changed, 125 insertions(+), 25 deletions(-) create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Sequence.java create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceService.java create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceServiceImpl.java diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Datasource.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Datasource.java index 2f22833f07..b7363ab494 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Datasource.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Datasource.java @@ -20,6 +20,10 @@ import java.util.Set; @NoArgsConstructor @Document public class Datasource extends BaseDomain { + + @Transient + public static final String DEFAULT_NAME_PREFIX = "Untitled Datasource"; + String name; String pluginId; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Sequence.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Sequence.java new file mode 100644 index 0000000000..3df075b6ff --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Sequence.java @@ -0,0 +1,12 @@ +package com.appsmith.server.domains; + +import lombok.Getter; + +public class Sequence { + + private String name; + + @Getter + private Long nextNumber; + +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java index e20c15727a..1d4d54b050 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java @@ -17,6 +17,7 @@ import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.PluginType; import com.appsmith.server.domains.Query; import com.appsmith.server.domains.Role; +import com.appsmith.server.domains.Sequence; import com.appsmith.server.domains.Setting; import com.appsmith.server.domains.User; import com.appsmith.server.dtos.OrganizationPluginStatus; @@ -31,7 +32,6 @@ import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.index.CompoundIndexDefinition; import org.springframework.data.mongodb.core.index.Index; import org.springframework.data.mongodb.core.index.IndexOperations; -import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.util.CollectionUtils; import java.time.Instant; @@ -42,6 +42,10 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.springframework.data.mongodb.core.query.Criteria.where; +import static org.springframework.data.mongodb.core.query.Query.query; +import static org.springframework.data.mongodb.core.query.Update.update; + @Slf4j @ChangeLog(order = "001") public class DatabaseChangelog { @@ -263,7 +267,7 @@ public class DatabaseChangelog { @ChangeSet(order = "006", id = "hide-rapidapi-plugin", author = "") public void hideRapidApiPluginFromCreateDatasource(MongoTemplate mongoTemplate) { final Plugin rapidApiPlugin = mongoTemplate.findOne( - org.springframework.data.mongodb.core.query.Query.query(Criteria.where("packageName").is("rapidapi-plugin")), + query(where("packageName").is("rapidapi-plugin")), Plugin.class ); @@ -341,7 +345,7 @@ public class DatabaseChangelog { @ChangeSet(order = "011", id = "install-default-plugins-to-all-organizations", author = "") public void installDefaultPluginsToAllOrganizations(MongoTemplate mongoTemplate) { final List defaultPlugins = mongoTemplate.find( - org.springframework.data.mongodb.core.query.Query.query(Criteria.where("defaultInstall").is(true)), + query(where("defaultInstall").is(true)), Plugin.class ); @@ -369,7 +373,7 @@ public class DatabaseChangelog { @ChangeSet(order = "012", id = "ensure-datasource-created-and-updated-at-fields", author = "") public void ensureDatasourceCreatedAndUpdatedAt(MongoTemplate mongoTemplate) { final List missingCreatedAt = mongoTemplate.find( - org.springframework.data.mongodb.core.query.Query.query(Criteria.where("createdAt").exists(false)), + query(where("createdAt").exists(false)), Datasource.class ); @@ -379,7 +383,7 @@ public class DatabaseChangelog { } final List missingUpdatedAt = mongoTemplate.find( - org.springframework.data.mongodb.core.query.Query.query(Criteria.where("updatedAt").exists(false)), + query(where("updatedAt").exists(false)), Datasource.class ); @@ -389,4 +393,29 @@ public class DatabaseChangelog { } } + @ChangeSet(order = "013", id = "add-index-for-sequence-name", author = "") + public void addIndexForSequenceName(MongoTemplate mongoTemplate) { + ensureIndexes(mongoTemplate, Sequence.class, + makeIndex(FieldName.NAME).unique() + ); + } + + @ChangeSet(order = "014", id = "set-initial-sequence-for-datasource", author = "") + public void setInitialSequenceForDatasource(MongoTemplate mongoTemplate) { + final Long maxUntitledDatasourceNumber = mongoTemplate.find( + query(where(FieldName.NAME).regex("^" + Datasource.DEFAULT_NAME_PREFIX + " \\d+$")), + Datasource.class + ) + .stream() + .map(datasource -> Long.parseLong(datasource.getName().split(" ")[2])) + .max(Long::compareTo) + .orElse(0L); + + mongoTemplate.upsert( + query(where(FieldName.NAME).is(mongoTemplate.getCollectionName(Datasource.class))), + update("nextNumber", maxUntitledDatasourceNumber + 1), + Sequence.class + ); + } + } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java index c84fa2d57a..3500c25e03 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java @@ -1,8 +1,6 @@ package com.appsmith.server.repositories; -import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Datasource; -import org.springframework.data.mongodb.repository.Query; import org.springframework.stereotype.Repository; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -15,6 +13,4 @@ public interface DatasourceRepository extends BaseRepository Flux findAllByOrganizationId(String organizationId); - @Query(value = "{" + FieldName.NAME + ": {$regex: ?0}}", count = true) - Mono countNamesByPrefix(String namePrefix); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java index afbea1a8d4..dd402918ab 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java @@ -16,7 +16,6 @@ public interface DatasourceService extends CrudService { Set extractKeysFromDatasource(Datasource datasource); - Mono getNextUniqueName(String initialSlug); - Mono validateDatasource(Datasource datasource); + } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java index 232df90bf0..b922aac557 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java @@ -42,6 +42,7 @@ public class DatasourceServiceImpl extends BaseService datasourceMono = Mono.just(datasource); if (StringUtils.isEmpty(datasource.getName())) { - datasourceMono = datasourceMono.zipWith( - getNextUniqueName("Untitled datasource"), - (datasource1, name) -> { - datasource1.setName(name); + datasourceMono = sequenceService + .getNextAsSuffix(Datasource.class) + .zipWith(datasourceMono, (sequenceNumber, datasource1) -> { + datasource1.setName(Datasource.DEFAULT_NAME_PREFIX + sequenceNumber); return datasource1; }); } - return datasourceMono.flatMap(this::validateAndSaveDatasourceToRepository); - } - - @Override - public Mono getNextUniqueName(String namePrefix) { - return repository.countNamesByPrefix(namePrefix) - .map(max -> namePrefix + (max == 0 ? "" : " " + (max + 1))); + return datasourceMono + .flatMap(this::validateAndSaveDatasourceToRepository); } @Override diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceService.java new file mode 100644 index 0000000000..c9dbda110c --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceService.java @@ -0,0 +1,14 @@ +package com.appsmith.server.services; + +import com.appsmith.external.models.BaseDomain; +import reactor.core.publisher.Mono; + +public interface SequenceService { + + Mono getNext(String name); + + Mono getNext(Class domainClass); + + Mono getNextAsSuffix(Class domainClass); + +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceServiceImpl.java new file mode 100644 index 0000000000..189715daad --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/SequenceServiceImpl.java @@ -0,0 +1,48 @@ +package com.appsmith.server.services; + +import com.appsmith.external.models.BaseDomain; +import com.appsmith.server.domains.Sequence; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import static org.springframework.data.mongodb.core.FindAndModifyOptions.options; +import static org.springframework.data.mongodb.core.query.Criteria.where; +import static org.springframework.data.mongodb.core.query.Query.query; + +@Service +public class SequenceServiceImpl implements SequenceService { + + private final ReactiveMongoTemplate mongoTemplate; + + @Autowired + public SequenceServiceImpl(ReactiveMongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + @Override + public Mono getNext(String name) { + return mongoTemplate + .findAndModify( + query(where("name").is(name)), + new Update().inc("nextNumber", 1), + options().upsert(true), + Sequence.class + ) + .map(Sequence::getNextNumber); + } + + @Override + public Mono getNext(Class domainClass) { + return getNext(mongoTemplate.getCollectionName(domainClass)); + } + + @Override + public Mono getNextAsSuffix(Class domainClass) { + return getNext(mongoTemplate.getCollectionName(domainClass)) + .map(number -> number > 1 ? " " + number : ""); + } + +} diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java index 0b6f66344d..a2332b28c2 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java @@ -253,12 +253,12 @@ public class DatasourceServiceTest { final Datasource ds1 = tuple2.getT1(); assertThat(ds1.getId()).isNotEmpty(); assertThat(ds1.getPluginId()).isEqualTo(datasource1.getPluginId()); - assertThat(ds1.getName()).isEqualTo("Untitled datasource"); + assertThat(ds1.getName()).isEqualTo("Untitled Datasource"); final Datasource ds2 = tuple2.getT2(); assertThat(ds2.getId()).isNotEmpty(); assertThat(ds2.getPluginId()).isEqualTo(datasource1.getPluginId()); - assertThat(ds2.getName()).isEqualTo("Untitled datasource 2"); + assertThat(ds2.getName()).isEqualTo("Untitled Datasource 2"); }) .verifyComplete(); }