From c0facd5ba286c336a7337d0597b61f0ec44dfecb Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sat, 8 Nov 2025 00:05:09 +0700 Subject: [PATCH] Refactor repository structure for Couchbase collections Introduced AbstractCollectionRepository and AbstractSingletonRepository to clarify repository types and encapsulate logic for single-key and collection-based repositories. Updated AdminRepository, AppleAppRepository, GoogleAppRepository, and GroupRepository to extend the appropriate abstract classes. Removed COMMON_COLLECTION_NAME from Constant.java and enforced collection name restrictions in AbstractRepository. --- .../storescraperbot/constant/Constant.java | 1 - .../AbstractCollectionRepository.java | 38 ++++++++++++++ .../repository/AbstractRepository.java | 25 +++++++--- .../AbstractSingletonRepository.java | 43 ++++++++++++++++ .../repository/AdminRepository.java | 50 ++----------------- .../repository/AppleAppRepository.java | 2 +- .../repository/GoogleAppRepository.java | 2 +- .../repository/GroupRepository.java | 2 +- 8 files changed, 104 insertions(+), 59 deletions(-) create mode 100644 src/main/java/com/miti99/storescraperbot/repository/AbstractCollectionRepository.java create mode 100644 src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java diff --git a/src/main/java/com/miti99/storescraperbot/constant/Constant.java b/src/main/java/com/miti99/storescraperbot/constant/Constant.java index de5f361..f768256 100644 --- a/src/main/java/com/miti99/storescraperbot/constant/Constant.java +++ b/src/main/java/com/miti99/storescraperbot/constant/Constant.java @@ -7,7 +7,6 @@ import java.time.temporal.ChronoUnit; import java.util.Set; public class Constant { - public static final String COMMON_COLLECTION_NAME = "common"; public static final long APP_CACHE_SECONDS = 600; public static final long NUM_DAYS_WARNING_NOT_UPDATED = 30; public static final LocalTime SCHEDULE_CHECK_APP_TIME = LocalTime.of(7, 0); diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractCollectionRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractCollectionRepository.java new file mode 100644 index 0000000..780079e --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractCollectionRepository.java @@ -0,0 +1,38 @@ +package com.miti99.storescraperbot.repository; + +import com.miti99.storescraperbot.model.AbstractModel; +import lombok.extern.log4j.Log4j2; + +/** + * Các repository tương ứng với 1 Couchbase collection, public các method protected ở class + * AbstractRepository để các nơi khác gọi + */ +@Log4j2 +public abstract class AbstractCollectionRepository> + extends AbstractRepository { + + @Override + public void init(K key) { + super.init(key); + } + + @Override + public void save(K key, V data) { + super.save(key, data); + } + + @Override + public boolean exist(K key) { + return super.exist(key); + } + + @Override + public V load(K key) { + return super.load(key); + } + + @Override + public void delete(K key) { + super.delete(key); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java index b6063d7..330c3e1 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java @@ -1,5 +1,7 @@ package com.miti99.storescraperbot.repository; +import static com.miti99.storescraperbot.repository.AbstractSingletonRepository.COMMON_COLLECTION_NAME; + import com.couchbase.client.java.Collection; import com.couchbase.client.java.kv.UpsertOptions; import com.google.common.base.CaseFormat; @@ -10,9 +12,13 @@ import java.lang.reflect.ParameterizedType; import java.time.Duration; import lombok.extern.log4j.Log4j2; +/** + * @param class Key + * @param class Value + */ @Log4j2 public abstract class AbstractRepository> { - public static final String SEPARATOR = "_"; + protected static final String SEPARATOR = "_"; // protected final Class classK = getKeyClass(); protected final Class classV = getDataClass(); protected final String scopeName = Environment.ENV.name().toLowerCase(); @@ -25,6 +31,10 @@ public abstract class AbstractRepository> { protected AbstractRepository() { collectionName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, classV.getSimpleName()); + if (COMMON_COLLECTION_NAME.equals(collectionName)) { + throw new RuntimeException( + "Collection named '%s' is reserved".formatted(COMMON_COLLECTION_NAME)); + } CouchbaseUtil.createCollection(scopeName, collectionName); } @@ -35,8 +45,7 @@ public abstract class AbstractRepository> { /** * Lấy ra class của V. Khi tạo 1 abstract class extends AbstractRepository mà không phải final thì - * sẽ cần override hàm này phù hợp
- * Chi tiết có thể tìm hiểu thêm về getGenericSuperclass và getParameterizedClass
+ * sẽ cần override hàm này phù hợp * * @return Class<V> */ @@ -56,7 +65,7 @@ public abstract class AbstractRepository> { return 0; } - public void init(K key) { + protected void init(K key) { try { if (exist(key)) { return; @@ -73,7 +82,7 @@ public abstract class AbstractRepository> { return String.valueOf(key); } - public void save(K key, V data) { + protected void save(K key, V data) { var databaseKey = getDatabaseKey(key); try { if (getExpireSeconds() == 0) { @@ -88,7 +97,7 @@ public abstract class AbstractRepository> { } } - public boolean exist(K key) { + protected boolean exist(K key) { var databaseKey = getDatabaseKey(key); try { return collection().exists(databaseKey).exists(); @@ -98,7 +107,7 @@ public abstract class AbstractRepository> { } } - public V load(K key) { + protected V load(K key) { var databaseKey = getDatabaseKey(key); try { var getResult = collection().get(databaseKey); @@ -112,7 +121,7 @@ public abstract class AbstractRepository> { } } - public void delete(K key) { + protected void delete(K key) { var databaseKey = getDatabaseKey(key); try { collection().remove(databaseKey); diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java new file mode 100644 index 0000000..a728a75 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractSingletonRepository.java @@ -0,0 +1,43 @@ +package com.miti99.storescraperbot.repository; + +import com.miti99.storescraperbot.model.AbstractModel; +import lombok.extern.log4j.Log4j2; + +/** + * Repository chỉ chứa 1 key duy nhất, public các method liên quan nhưng không cho truyền params + * vào. Các repository loại này được lưu trong 1 collection duy nhất là "common" (do Couchbase có + * giới hạn số lượng collection mỗi cluster nên gom nhóm các repository loại này lại) + */ +@Log4j2 +public abstract class AbstractSingletonRepository> + extends AbstractRepository { + + public static final String COMMON_COLLECTION_NAME = "common"; + protected final K key = getKey(); + + protected AbstractSingletonRepository() { + super(COMMON_COLLECTION_NAME); + } + + protected abstract K getKey(); + + public void init() { + init(key); + } + + public void save(V data) { + save(key, data); + } + + public boolean exist() { + return exist(key); + } + + public V load() { + return load(key); + } + + public void delete() { + delete(key); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java index a24f5a8..420cf6f 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java @@ -1,57 +1,13 @@ package com.miti99.storescraperbot.repository; -import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.Admin; -/** - * Đây là repository chỉ chứa 1 key duy nhất. Nên lưu trong default collection của Couchbase - * ("_default") - * - *

TODO: Refactor các logic của một single key repository sang abstract class để dễ hiểu hơn. - * Code hiện tại này chỉ là trick tạm thời nên chưa tốt lắm. Cần thiết kế lại tốt hơn - */ -public class AdminRepository extends AbstractRepository { +public class AdminRepository extends AbstractSingletonRepository { public static final AdminRepository INSTANCE = new AdminRepository(); public static final String KEY = "admin"; - public AdminRepository() { - super(Constant.COMMON_COLLECTION_NAME); - } - @Override - public void init(String key) { - super.init(KEY); - } - - @Override - public void save(String key, Admin data) { - super.save(KEY, data); - } - - @Override - public boolean exist(String key) { - return super.exist(KEY); - } - - @Override - public Admin load(String key) { - return super.load(KEY); - } - - @Override - public void delete(String key) { - super.delete(KEY); - } - - public void init() { - init(KEY); - } - - public Admin load() { - return load(KEY); - } - - public void save(Admin data) { - save(KEY, data); + protected String getKey() { + return KEY; } } diff --git a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java index 733d935..6309e88 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java @@ -3,7 +3,7 @@ package com.miti99.storescraperbot.repository; import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.AppleApp; -public class AppleAppRepository extends AbstractRepository { +public class AppleAppRepository extends AbstractCollectionRepository { public static final AppleAppRepository INSTANCE = new AppleAppRepository(); @Override diff --git a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java index 92835fb..707bf04 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java @@ -3,7 +3,7 @@ package com.miti99.storescraperbot.repository; import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.GoogleApp; -public class GoogleAppRepository extends AbstractRepository { +public class GoogleAppRepository extends AbstractCollectionRepository { public static final GoogleAppRepository INSTANCE = new GoogleAppRepository(); @Override diff --git a/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java b/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java index a47798e..157f697 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/GroupRepository.java @@ -2,6 +2,6 @@ package com.miti99.storescraperbot.repository; import com.miti99.storescraperbot.model.Group; -public class GroupRepository extends AbstractRepository { +public class GroupRepository extends AbstractCollectionRepository { public static final GroupRepository INSTANCE = new GroupRepository(); }