diff --git a/inset-core/src/main/java/slatepowered/inset/datastore/Datastore.java b/inset-core/src/main/java/slatepowered/inset/datastore/Datastore.java index 6d75bc4..defffdb 100644 --- a/inset-core/src/main/java/slatepowered/inset/datastore/Datastore.java +++ b/inset-core/src/main/java/slatepowered/inset/datastore/Datastore.java @@ -11,6 +11,7 @@ import slatepowered.inset.query.QueryStatus; import slatepowered.inset.source.DataTable; +import java.util.Optional; import java.util.function.Predicate; /** @@ -69,6 +70,17 @@ public DataItem getOrCreate(K key) { return getOrReference(key).defaultIfAbsent(); } + /** + * Get a cached data item by the given key, returning an + * empty optional if absent. + * + * @param key The key. + * @return The optional with the value if present. + */ + public Optional> getOptional(K key) { + return Optional.ofNullable(dataCache.getOrNull(key)); + } + /** * Get an existent (potentially empty) data item for the given key or * return null if absent. diff --git a/inset-core/src/main/java/slatepowered/inset/query/QueryStatus.java b/inset-core/src/main/java/slatepowered/inset/query/QueryStatus.java index efc81bc..ef21fd3 100644 --- a/inset-core/src/main/java/slatepowered/inset/query/QueryStatus.java +++ b/inset-core/src/main/java/slatepowered/inset/query/QueryStatus.java @@ -4,9 +4,10 @@ import slatepowered.inset.datastore.Datastore; import slatepowered.inset.datastore.OperationStatus; -import java.util.concurrent.CompletableFuture; +import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; /** * Represents an awaitable query status/result. @@ -58,7 +59,7 @@ public QueryStatus thenDefaultIfAbsent() { return this; future = future.thenApply(status -> { - if (status.absent()) { + if (status.isAbsent()) { this.item = datastore.getOrCreate(key()); } @@ -76,7 +77,7 @@ public QueryStatus thenDefaultIfAbsent() { */ public QueryStatus thenFetchIfCached() { future = future.thenApplyAsync(status -> { - if (status.cached()) { + if (status.wasCached()) { status.item().fetchSync(); } @@ -100,6 +101,20 @@ public QueryStatus ifPresent(Consumer> consumer) { return this; } + /** + * If a value is absent, run the given consumer. + * + * @param consumer The consumer. + * @return This. + */ + public QueryStatus ifAbsent(Consumer> consumer) { + if (isAbsent()) { + consumer.accept(this); + } + + return this; + } + /** * If a value is present, run the given consumer. * @@ -156,6 +171,44 @@ public QueryStatus thenApply(Consumer> action) { return this; } + /** + * Add a new synchronous action to be executed when the previous + * stage of this query finishes with a value. + * + * @param action The action. + * @return This. + */ + public QueryStatus thenApplyIfPresent(Consumer> action) { + future = future.thenApply(status -> { + if (status.isPresent()) { + action.accept(status); + } + + return status; + }); + + return this; + } + + /** + * Add a new synchronous action to be executed when the previous + * stage of this query finishes without a value. + * + * @param action The action. + * @return This. + */ + public QueryStatus thenApplyIfAbsent(Consumer> action) { + future = future.thenApply(status -> { + if (status.isAbsent()) { + action.accept(status); + } + + return status; + }); + + return this; + } + /** * When the query fails, call the given consumer. * @@ -216,11 +269,83 @@ public DataItem item() { } /** - * Get the key of the resolved item, this may - * be null if the query failed or is not completed yet. + * Get an optional for the result data item, which will + * be present if the query succeeded and found an item. + * + * @return The optional present if an item is present. + */ + public Optional> optional() { + return Optional.ofNullable(item); + } + + /** + * Get the resolved item or create a new reference + * item. + * + * @return The item. + */ + public DataItem orReference() { + K key = key(); + if (key == null) + throw new IllegalStateException("No key was resolved or set in the query"); + return item != null ? item : (item = datastore.getOrReference(key())); + } + + /** + * Get the resolved item or create a new one with + * the default value. + * + * @return The item. + */ + public DataItem orCreate() { + K key = key(); + if (key == null) + throw new IllegalStateException("No key was resolved or set in the query"); + return item != null ? item : (item = datastore.getOrCreate(key())); + } + + /** + * Get the resolved item if present or return the given default. + * + * @param def The default option. + * @return The resolved item is present or the given default. + */ + public DataItem orElse(DataItem def) { + return item != null ? item : (item = def); + } + + /** + * Get the resolved item if present or compute and return + * a default value using the given default supplier. + * + * @param supplier The default supplier. + * @return The resolved item is present or the default value. + */ + public DataItem orElseGet(Supplier> supplier) { + return item != null ? item : (item = supplier.get()); + } + + /** + * Get the resolved item if present or compute and return + * a default value using the given default action. + * + * @param action The default action. + * @return The resolved item is present or the default value. */ + public DataItem orElseCompute(Function, DataItem> action) { + return item != null ? item : (item = action.apply(this)); + } + + /** + * Get the key of the query/resolved item, this may + * be null if the query does not have a key set and is absent, + * failed or is not completed yet. + */ + @SuppressWarnings("unchecked") public K key() { - return item != null ? item.key() : null; + if (item != null) return item.key(); + if (query.hasKey()) return (K) query.getKey(); + return null; } /** @@ -274,15 +399,15 @@ public boolean isPresent() { return result != null && result.isValue(); } - public boolean absent() { + public boolean isAbsent() { return result != null && !result.isValue(); } - public boolean cached() { + public boolean wasCached() { return result != null && result == QueryResult.CACHED; } - public boolean fetched() { + public boolean wasFetched() { return result != null && result == QueryResult.FETCHED; } diff --git a/inset-mongodb/src/test/java/example/slatepowered/inset/MongoDatastoreExample.java b/inset-mongodb/src/test/java/example/slatepowered/inset/MongoDatastoreExample.java index b781dd7..1464249 100644 --- a/inset-mongodb/src/test/java/example/slatepowered/inset/MongoDatastoreExample.java +++ b/inset-mongodb/src/test/java/example/slatepowered/inset/MongoDatastoreExample.java @@ -55,17 +55,17 @@ public static void main(String[] args) throws InterruptedException { // This is called if the query succeeds, this doesn't mean // it would've found anything it just means no errors occurred - if (result.absent()) { // No item found in database or locally + if (result.isAbsent()) { // No item found in database or locally System.out.println("Could not find item, inserting new item with key: " + key); datastore.getOrCreate(key).ifPresent(stats -> stats.deaths++).saveSync(); return; } - if (result.cached()) { // Item was cached + if (result.wasCached()) { // Item was cached } - if (result.fetched()) { // Item was loaded from the database + if (result.wasFetched()) { // Item was loaded from the database }