diff --git a/pom.xml b/pom.xml index 7931107..657ac3d 100644 --- a/pom.xml +++ b/pom.xml @@ -154,6 +154,25 @@ + + + com.fasterxml.jackson.core + jackson-core + 2.17.1 + + + + com.fasterxml.jackson.core + jackson-annotations + 2.17.1 + + + + com.fasterxml.jackson.core + jackson-databind + 2.17.1 + + \ No newline at end of file diff --git a/src/main/java/xyz/refinedev/api/storage/mongo/MongoStorage.java b/src/main/java/xyz/refinedev/api/storage/mongo/MongoStorage.java deleted file mode 100644 index 2dd3e5c..0000000 --- a/src/main/java/xyz/refinedev/api/storage/mongo/MongoStorage.java +++ /dev/null @@ -1,131 +0,0 @@ -package xyz.refinedev.api.storage.mongo; - -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -import com.mongodb.client.MongoCollection; -import com.mongodb.client.model.Filters; -import com.mongodb.client.model.ReplaceOptions; - -import com.mongodb.client.model.Updates; -import org.bson.Document; -import org.bson.conversions.Bson; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -/** - * This Project is property of Refine Development © 2021 - 2022 - * Redistribution of this Project is not allowed - * - * @author Drizzy - * Created: 7/27/2022 - * Project: StorageAPI - */ - -@SuppressWarnings("unused") -public class MongoStorage { - - private static final ReplaceOptions REPLACE_OPTIONS = new ReplaceOptions().upsert(true); - - private final MongoCollection collection; - private final Gson gson; - private final Type typeToken; - - public MongoStorage(MongoCollection collection, Gson gson) { - this.collection = collection; - this.gson = gson; - this.typeToken = new TypeToken() {}.getType(); - } - - public CompletableFuture> fetchAllEntries() { - return CompletableFuture.supplyAsync(() -> { - List found = new ArrayList<>(); - for (Document document : this.collection.find()) { - if (document == null) { - continue; - } - found.add(this.gson.fromJson(document.toJson(), typeToken)); - } - return found; - }); - } - - public CompletableFuture> fetchAllRawEntries() { - return CompletableFuture.supplyAsync(() -> { - List found = new ArrayList<>(); - for (Document document : this.collection.find()) { - found.add(document); - } - return found; - }); - } - - public void saveData(UUID key, V value, Type type) { - CompletableFuture.runAsync(() -> this.saveDataSync(key, value, type)); - } - - public void saveDataSync(UUID key, V value, Type type) { - Bson query = Filters.eq("_id", key.toString()); - Document parsed = Document.parse(gson.toJson(value, type)); - this.collection.replaceOne(query, parsed, REPLACE_OPTIONS); - } - - public void saveRawData(UUID key, Document document) { - CompletableFuture.runAsync(() -> this.saveRawDataSync(key, document)); - } - - public void saveRawDataSync(UUID key, Document document) { - Bson query = Filters.eq("_id", key.toString()); - this.collection.replaceOne(query, document, REPLACE_OPTIONS); - } - - public V loadData(UUID key, Type type) { - Bson query = Filters.eq("_id", key.toString()); - - Document document = this.collection.find(query).first(); - if (document == null) return null; - - return this.gson.fromJson(document.toJson(), type); - } - - public CompletableFuture loadDataAsync(UUID key, Type type) { - return CompletableFuture.supplyAsync(() -> this.loadData(key, type)); - } - - public Document loadRawData(UUID key) { - Bson query = Filters.eq("_id", key.toString()); - return this.collection.find(query).first(); - } - - public CompletableFuture loadRawDataAsync(UUID key) { - return CompletableFuture.supplyAsync(() -> this.loadRawData(key)); - } - - public void deleteData(UUID key) { - CompletableFuture.runAsync(() -> { - Bson query = Filters.eq("_id", key.toString()); - this.collection.deleteOne(query); - }); - } - - /** - * Delete a certain key in all documents inside the collection - * Uses long because it could surpass the limit of integer - * - * @param key {@link String key} - * @return {@link Integer amount of deleted documents} - */ - public CompletableFuture deleteKeyInAll(String key) { - return CompletableFuture.supplyAsync(() -> { - // Unset the key - Bson combinedUpdate = Updates.unset(key); - - // Apply the updates to all documents in the collection - return collection.updateMany(new Document(), combinedUpdate).getModifiedCount(); // new Document() is an empty filter, meaning "all documents"; - }); - } -} diff --git a/src/main/java/xyz/refinedev/api/storage/mongo/model/Model.java b/src/main/java/xyz/refinedev/api/storage/mongo/model/Model.java new file mode 100644 index 0000000..13ad9d4 --- /dev/null +++ b/src/main/java/xyz/refinedev/api/storage/mongo/model/Model.java @@ -0,0 +1,9 @@ +package xyz.refinedev.api.storage.mongo.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public interface Model { + + @JsonProperty("_id") + String getId(); +} diff --git a/src/main/java/xyz/refinedev/api/storage/mongo/repository/MongoObjectRepository.java b/src/main/java/xyz/refinedev/api/storage/mongo/repository/MongoObjectRepository.java new file mode 100644 index 0000000..dc0cbe3 --- /dev/null +++ b/src/main/java/xyz/refinedev/api/storage/mongo/repository/MongoObjectRepository.java @@ -0,0 +1,40 @@ +package xyz.refinedev.api.storage.mongo.repository; + +import com.google.common.collect.Lists; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.ReplaceOptions; +import lombok.RequiredArgsConstructor; +import xyz.refinedev.api.storage.mongo.model.Model; + +import java.util.List; + +@RequiredArgsConstructor +public class MongoObjectRepository implements ObjectRepository { + + private final MongoCollection collection; + + @Override + public O find(String id) { + return collection.find(Filters.eq("_id", id)).first(); + } + + @Override + public void remove(String id) { + collection.deleteOne(Filters.eq("_id", id)); + } + + @Override + public void save(O model) { + collection.replaceOne( + Filters.eq("_id", model.getId()), + model, + new ReplaceOptions().upsert(true) + ); + } + + @Override + public List findAll() { + return collection.find().into(Lists.newArrayList()); + } +} diff --git a/src/main/java/xyz/refinedev/api/storage/mongo/repository/ObjectRepository.java b/src/main/java/xyz/refinedev/api/storage/mongo/repository/ObjectRepository.java new file mode 100644 index 0000000..2fed114 --- /dev/null +++ b/src/main/java/xyz/refinedev/api/storage/mongo/repository/ObjectRepository.java @@ -0,0 +1,12 @@ +package xyz.refinedev.api.storage.mongo.repository; + +import xyz.refinedev.api.storage.mongo.model.Model; + +import java.util.List; + +public interface ObjectRepository { + O find(String id); + void remove(String id); + void save(O model); + List findAll(); +} diff --git a/src/main/java/xyz/refinedev/api/storage/mongo/storage/MongoStorage.java b/src/main/java/xyz/refinedev/api/storage/mongo/storage/MongoStorage.java new file mode 100644 index 0000000..29fa3f8 --- /dev/null +++ b/src/main/java/xyz/refinedev/api/storage/mongo/storage/MongoStorage.java @@ -0,0 +1,124 @@ +package xyz.refinedev.api.storage.mongo.storage; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.ReplaceOptions; + +import com.mongodb.client.model.Updates; +import lombok.RequiredArgsConstructor; +import org.bson.Document; +import org.bson.conversions.Bson; +import xyz.refinedev.api.storage.mongo.model.Model; +import xyz.refinedev.api.storage.mongo.repository.MongoObjectRepository; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +/** + * This Project is property of Refine Development © 2021 - 2022 + * Redistribution of this Project is not allowed + * + * @author Drizzy + * Created: 7/27/2022 + * Project: StorageAPI + * + * Legacy implementation using {@link Document} + Gson. + * + * @deprecated Use {@link MongoStorageManager} with typed repositories instead. + */ + +@Deprecated +@SuppressWarnings("unused") +@RequiredArgsConstructor +public class MongoStorage { + + private static final ReplaceOptions REPLACE_OPTIONS = new ReplaceOptions().upsert(true); + + private final MongoCollection collection; + private final Gson gson; + private final Type typeToken = new TypeToken() {}.getType(); + + public MongoObjectRepository asRepository(MongoCollection typedCollection) { + return new MongoObjectRepository<>(typedCollection); + } + + public CompletableFuture> fetchAllEntries() { + return CompletableFuture.supplyAsync(() -> { + List found = new ArrayList<>(); + for (Document document : this.collection.find()) { + if (document == null) continue; + found.add(this.gson.fromJson(document.toJson(), typeToken)); + } + return found; + }); + } + + public CompletableFuture> fetchAllRawEntries() { + return CompletableFuture.supplyAsync(() -> { + List found = new ArrayList<>(); + for (Document document : this.collection.find()) { + found.add(document); + } + return found; + }); + } + + public void saveData(UUID key, V value, Type type) { + CompletableFuture.runAsync(() -> this.saveDataSync(key, value, type)); + } + + public void saveDataSync(UUID key, V value, Type type) { + Bson query = Filters.eq("_id", key.toString()); + Document parsed = Document.parse(gson.toJson(value, type)); + this.collection.replaceOne(query, parsed, REPLACE_OPTIONS); + } + + public void saveRawData(UUID key, Document document) { + CompletableFuture.runAsync(() -> this.saveRawDataSync(key, document)); + } + + public void saveRawDataSync(UUID key, Document document) { + Bson query = Filters.eq("_id", key.toString()); + this.collection.replaceOne(query, document, REPLACE_OPTIONS); + } + + public V loadData(UUID key, Type type) { + Bson query = Filters.eq("_id", key.toString()); + Document document = this.collection.find(query).first(); + if (document == null) return null; + return this.gson.fromJson(document.toJson(), type); + } + + public CompletableFuture loadDataAsync(UUID key, Type type) { + return CompletableFuture.supplyAsync(() -> this.loadData(key, type)); + } + + public Document loadRawData(UUID key) { + Bson query = Filters.eq("_id", key.toString()); + return this.collection.find(query).first(); + } + + public CompletableFuture loadRawDataAsync(UUID key) { + return CompletableFuture.supplyAsync(() -> this.loadRawData(key)); + } + + public void deleteData(UUID key) { + CompletableFuture.runAsync(() -> { + Bson query = Filters.eq("_id", key.toString()); + this.collection.deleteOne(query); + }); + } + + public CompletableFuture deleteKeyInAll(String key) { + return CompletableFuture.supplyAsync(() -> { + Bson combinedUpdate = Updates.unset(key); + return collection.updateMany(new Document(), combinedUpdate).getModifiedCount(); + }); + } +} \ No newline at end of file diff --git a/src/main/java/xyz/refinedev/api/storage/mongo/storage/MongoStorageManager.java b/src/main/java/xyz/refinedev/api/storage/mongo/storage/MongoStorageManager.java new file mode 100644 index 0000000..d126d54 --- /dev/null +++ b/src/main/java/xyz/refinedev/api/storage/mongo/storage/MongoStorageManager.java @@ -0,0 +1,49 @@ +package xyz.refinedev.api.storage.mongo.storage; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import lombok.Getter; +import xyz.refinedev.api.storage.mongo.model.Model; +import xyz.refinedev.api.storage.mongo.repository.MongoObjectRepository; +import xyz.refinedev.api.storage.mongo.repository.ObjectRepository; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.codecs.pojo.PojoCodecProvider; + +import static org.bson.codecs.configuration.CodecRegistries.*; + +@Getter +public class MongoStorageManager { + + private final MongoClient client; + private final MongoDatabase database; + + public MongoStorageManager(String connectionUri, String dbName) { + ConnectionString connString = new ConnectionString(connectionUri); + + CodecRegistry pojoCodecRegistry = fromRegistries( + MongoClientSettings.getDefaultCodecRegistry(), + fromProviders(PojoCodecProvider.builder().automatic(true).build()) + ); + + MongoClientSettings settings = MongoClientSettings.builder() + .applyConnectionString(connString) + .codecRegistry(pojoCodecRegistry) + .build(); + + this.client = MongoClients.create(settings); + this.database = client.getDatabase(dbName); + } + + public ObjectRepository getRepository(Class clazz, String collectionName) { + MongoCollection collection = database.getCollection(collectionName, clazz); + return new MongoObjectRepository<>(collection); + } + + public void close() { + client.close(); + } +} diff --git a/src/test/java/dev/joordih/api/storage/Storage.java b/src/test/java/dev/joordih/api/storage/Storage.java new file mode 100644 index 0000000..fec3a02 --- /dev/null +++ b/src/test/java/dev/joordih/api/storage/Storage.java @@ -0,0 +1,34 @@ +package dev.joordih.api.storage; + +import dev.joordih.api.storage.user.User; +import dev.joordih.api.storage.user.UserManager; +import xyz.refinedev.api.storage.mongo.storage.MongoStorageManager; + +import java.util.UUID; + +public class Storage { + + public static void main(String[] args) { + MongoStorageManager storage = new MongoStorageManager( + "mongodb://localhost:27017", + "storage-api" + ); + + UserManager userManager = new UserManager(storage); + + UUID userUuid = UUID.randomUUID(); + User user = User.builder() + .id(userUuid.toString()) + .uuid(userUuid) + .points(100) + .level(1) + .build(); + + userManager.getRepository().save(user); + + User loadedUser = userManager.getRepository().find(userUuid.toString()); + System.out.println(loadedUser); + + storage.close(); + } +} diff --git a/src/test/java/dev/joordih/api/storage/user/User.java b/src/test/java/dev/joordih/api/storage/user/User.java new file mode 100644 index 0000000..14c2332 --- /dev/null +++ b/src/test/java/dev/joordih/api/storage/user/User.java @@ -0,0 +1,28 @@ +package dev.joordih.api.storage.user; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import xyz.refinedev.api.storage.mongo.model.Model; + +import java.util.UUID; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class User implements Model { + + @JsonProperty("_id") + private String id; + + private UUID uuid; + private int points; + private int level; + + @JsonIgnore + public boolean isPremium() { + return points >= 1000; + } +} diff --git a/src/test/java/dev/joordih/api/storage/user/UserManager.java b/src/test/java/dev/joordih/api/storage/user/UserManager.java new file mode 100644 index 0000000..efba6e8 --- /dev/null +++ b/src/test/java/dev/joordih/api/storage/user/UserManager.java @@ -0,0 +1,15 @@ +package dev.joordih.api.storage.user; + +import lombok.Getter; +import xyz.refinedev.api.storage.mongo.repository.ObjectRepository; +import xyz.refinedev.api.storage.mongo.storage.MongoStorageManager; + +@Getter +public class UserManager { + + private final ObjectRepository repository; + + public UserManager(MongoStorageManager storageManager) { + this.repository = storageManager.getRepository(User.class, "users"); + } +}