From 3c6d51ffc0a2025863dfa62b69a66ebbfeec8bf7 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Tue, 28 Oct 2025 20:40:11 +0700 Subject: [PATCH] Add abstract model and repository base classes Introduces AbstractModel and AbstractRepository to provide base classes for data models and repository operations. These classes establish common fields, Couchbase integration, and generic CRUD methods to streamline future model and repository implementations. --- .../storescraperbot/model/AbstractModel.java | 14 +++ .../repository/AbstractRepository.java | 98 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/main/java/com/miti99/storescraperbot/model/AbstractModel.java create mode 100644 src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java diff --git a/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java new file mode 100644 index 0000000..e089d5f --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java @@ -0,0 +1,14 @@ +package com.miti99.storescraperbot.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +public abstract class AbstractModel { + + @JsonProperty("class") + protected String clazz = getClass().getSimpleName(); + + @Setter protected K key; +} diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java new file mode 100644 index 0000000..1048213 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java @@ -0,0 +1,98 @@ +package com.miti99.storescraperbot.repository; + +import com.couchbase.client.java.Collection; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.miti99.storescraperbot.model.AbstractModel; +import com.miti99.storescraperbot.util.CouchbaseUtil; +import java.lang.reflect.ParameterizedType; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public abstract class AbstractRepository> { + public static final String SEPARATOR = "_"; + // protected static ObjectMapper objectMapper = new ObjectMapper(); + protected final Class classV = getDataClass(); + // protected final JavaType type = objectMapper.getTypeFactory().constructType(classV); + protected final String scopeName; + protected final String collectionName; + + protected AbstractRepository(String scopeName, String collectionName) { + this.scopeName = scopeName; + this.collectionName = collectionName; + } + + public Collection collection() { + return CouchbaseUtil.BUCKET.scope(scopeName).collection(collectionName); + } + + /** + * 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
+ * + * @return Class<V> + */ + protected Class getDataClass() { + return (Class) + ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1]; + } + + public void init(K key) { + try { + if (exist(key)) { + return; + } + V data = classV.getDeclaredConstructor().newInstance(); + save(key, data); + } catch (Exception e) { + log.error("Error while initializing data", e); + } + } + + protected String getDatabaseKey(K key) { + return String.join(SEPARATOR, classV.getSimpleName(), String.valueOf(key)); + } + + public void save(K key, V data) { + var databaseKey = getDatabaseKey(key); + try { + collection().upsert(databaseKey, data); + } catch (Exception e) { + log.error("save error - key {}, databaseKey {}", key, databaseKey, e); + } + } + + public boolean exist(K key) { + var databaseKey = getDatabaseKey(key); + try { + return collection().exists(databaseKey).exists(); + } catch (Exception e) { + log.error("exist error - key {}, databaseKey {}", key, databaseKey, e); + return false; + } + } + + public V load(K key) { + var databaseKey = getDatabaseKey(key); + try { + var getResult = collection().get(databaseKey); + if (getResult == null) { + return null; + } + return getResult.contentAs(classV); + } catch (Exception e) { + log.error("load error - key {}, databaseKey {}", key, databaseKey, e); + return null; + } + } + + public void delete(K key) { + var databaseKey = getDatabaseKey(key); + try { + collection().remove(databaseKey); + } catch (Exception e) { + log.error("delete error", e); + } + } +}