From ed8b789389989095d60e32ee08cfc359cc709f45 Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Mon, 17 Jul 2023 13:53:41 +0200 Subject: [PATCH] Allows configuring the Redis data source with type references The Redis data source used Class to configure the type safety. Unfortunately, it didn't work with generics. This commit adds methods using (Jackson) TypeReference to configure the various groups. Thus, generics are now supported. Also: - deprecate the graph group, as Redis declared it is as end-of-life ( :-( ) - deprecate search(Class keyType) as the index must be a string - re-structure a bit the Redis reference guide --- docs/src/main/asciidoc/redis-reference.adoc | 105 ++++-- .../cache/redis/runtime/RedisCacheImpl.java | 2 +- .../datasource/ReactiveRedisDataSource.java | 350 +++++++++++++++++ .../redis/datasource/RedisDataSource.java | 356 +++++++++++++++++- .../redis/datasource/codecs/Codecs.java | 35 +- .../AbstractAutoSuggestCommands.java | 4 +- .../datasource/AbstractBitMapCommands.java | 3 +- .../datasource/AbstractBloomCommands.java | 4 +- .../datasource/AbstractCountMinCommands.java | 3 +- .../datasource/AbstractCuckooCommands.java | 4 +- .../datasource/AbstractGeoCommands.java | 5 +- .../datasource/AbstractGraphCommands.java | 3 +- .../datasource/AbstractHashCommands.java | 7 +- .../AbstractHyperLogLogCommands.java | 4 +- .../datasource/AbstractJsonCommands.java | 3 +- .../datasource/AbstractKeyCommands.java | 5 +- .../datasource/AbstractListCommands.java | 7 +- .../datasource/AbstractSearchCommands.java | 8 +- .../datasource/AbstractSetCommands.java | 5 +- .../datasource/AbstractSortedSetCommands.java | 7 +- .../datasource/AbstractStreamCommands.java | 5 +- .../datasource/AbstractStringCommands.java | 5 +- .../AbstractTimeSeriesCommands.java | 3 +- .../datasource/AbstractTopKCommands.java | 3 +- .../BlockingRedisDataSourceImpl.java | 94 +++++ .../datasource/HScanReactiveCursorImpl.java | 9 +- .../redis/runtime/datasource/Marshaller.java | 36 +- .../ReactiveAutoSuggestCommandsImpl.java | 3 +- .../ReactiveBitMapCommandsImpl.java | 3 +- .../datasource/ReactiveBloomCommandsImpl.java | 3 +- .../ReactiveCountMinCommandsImpl.java | 3 +- .../ReactiveCuckooCommandsImpl.java | 3 +- .../datasource/ReactiveGeoCommandsImpl.java | 3 +- .../datasource/ReactiveHashCommandsImpl.java | 3 +- .../ReactiveHyperLogLogCommandsImpl.java | 4 +- .../datasource/ReactiveJsonCommandsImpl.java | 3 +- .../datasource/ReactiveKeyCommandsImpl.java | 3 +- .../datasource/ReactiveListCommandsImpl.java | 3 +- .../ReactivePubSubCommandsImpl.java | 5 +- .../ReactiveRedisDataSourceImpl.java | 95 ++++- .../ReactiveSearchCommandsImpl.java | 5 +- .../datasource/ReactiveSetCommandsImpl.java | 3 +- .../runtime/datasource/ReactiveSortable.java | 5 +- .../ReactiveSortedSetCommandsImpl.java | 3 +- .../ReactiveStreamCommandsImpl.java | 11 +- .../ReactiveStringCommandsImpl.java | 3 +- .../ReactiveTimeSeriesCommandsImpl.java | 5 +- .../datasource/ReactiveTopKCommandsImpl.java | 9 +- .../datasource/SScanReactiveCursorImpl.java | 5 +- .../datasource/ScanReactiveCursorImpl.java | 5 +- .../datasource/ZScanReactiveCursorImpl.java | 5 +- .../datasource/AutoSuggestCommandsTest.java | 57 +++ .../redis/datasource/BitMapCommandsTest.java | 18 + .../redis/datasource/BloomCommandsTest.java | 18 + .../datasource/CountMinCommandsTest.java | 22 ++ .../redis/datasource/CuckooCommandsTest.java | 20 + .../redis/datasource/GeoCommandsTest.java | 28 ++ .../redis/datasource/HashCommandsTest.java | 30 ++ .../datasource/HyperLogLogCommandsTest.java | 16 + .../redis/datasource/JsonCommandsTest.java | 18 + .../redis/datasource/KeyCommandsTest.java | 26 ++ .../redis/datasource/ListCommandTest.java | 14 + .../redis/datasource/PubSubCommandsTest.java | 25 ++ .../redis/datasource/SetCommandsTest.java | 15 + .../datasource/SortedSetCommandsTest.java | 16 + .../redis/datasource/StreamCommandsTest.java | 21 ++ .../datasource/TimeSeriesCommandsTest.java | 28 ++ .../redis/datasource/TopKCommandsTest.java | 36 ++ .../redis/datasource/ValueCommandsTest.java | 44 +++ 69 files changed, 1583 insertions(+), 137 deletions(-) diff --git a/docs/src/main/asciidoc/redis-reference.adoc b/docs/src/main/asciidoc/redis-reference.adoc index f802c34766e96..187cf380812cd 100644 --- a/docs/src/main/asciidoc/redis-reference.adoc +++ b/docs/src/main/asciidoc/redis-reference.adoc @@ -21,7 +21,7 @@ Typically, we recommend: This extension provides imperative and reactive APIs and low-level and high-level (type-safe) clients. -== Installation +== Use the Redis Client If you want to use this extension, you need to add the `io.quarkus:quarkus-redis` extension first. In your `pom.xml` file, add: @@ -85,7 +85,7 @@ To help you select the suitable API for you, here are some recommendations: * If you have existing Vert.x code, use `io.vertx.redis.client.RedisAPI` * If you need to emit custom commands, you can either use the data sources (reactive or imperative) or the `io.vertx.mutiny.redis.client.Redis`. -== Default and named clients +== Inject the default and named clients This extension lets you configure a _default_ Redis client/data sources or _named_ ones. The latter is essential when you need to connect to multiple Redis instances. @@ -135,7 +135,7 @@ public class RedisExample { TIP: You can omit the `@Inject` annotation when using `@RedisClientName`. -== Connection to Redis +== Connect to the Redis server The Redis extension can operate in 4 distinct modes: @@ -151,7 +151,7 @@ The connection url is configured with the `quarkus.redis.hosts` (or `quarkus.red quarkus.redis.hosts=redis://[:password@]host[:port][/db-number] ---- -=== Unix Socket +=== Use Unix Socket When using unix-socket, you need: @@ -160,7 +160,7 @@ When using unix-socket, you need: quarkus.redis.hosts=unix://[:password@]/domain/docker.sock[?select=db-number] ---- -=== Sentinel Mode +=== Use the Sentinel Mode When using Sentinel, you need to pass multiple _host urls_ and configure the client type to `sentinel`: @@ -174,7 +174,7 @@ quarkus.redis.master-name=my-sentinel # Default is my-master quarkus.redis.role=master # master is the default ---- -=== Cluster Mode +=== Use the Cluster Mode When using Redis in cluster mode, you need to pass multiple _host urls_, configure the client type to `cluster` and configure the `replicas` mode: @@ -185,7 +185,7 @@ quarkus.redis.client-type=cluster quarkus.redis.replicas=share ---- -=== Replication Mode +=== Use the replication Mode When using the replication mode, you need to pass a single host url and configure the type to be `replication`: @@ -195,7 +195,7 @@ quarkus.redis.hosts=redis://localhost:7000 quarkus.redis.client-type=replication ---- -=== Redis Cloud +=== Connect to Redis Cloud To connect to redis cloud, you need the following properties: @@ -205,14 +205,21 @@ quarkus.redis.hosts= ---- -=== Authentication +=== Use TLS + +To use TLS, you need to: + +1. Set the `quarkus.redis.tls.enabled=true` property +2. Make sure that your URL starts with `rediss://` (with two `s`) + +=== Configure the authentication The Redis password can be set in the `redis://` URL or with the `quarkus.redis.password` property. We recommend the latter, and if possible, using secrets or an environment variable to configure the password. The associated environment variable is `QUARKUS_REDIS_PASSWORD`, or `QUARKUS_REDIS__PASSWORD` for named clients. -== Quarkus client API for data sources +== Use Redis data sources Quarkus exposes a high-level API on top of Redis. This API is type-safe and structured around the notion of _group_, inherited from the https://redis.io/commands/command-docs/[Redis command organization]. @@ -263,7 +270,6 @@ The `ReactiveRedisDataSource` is implemented on top of the `io.vertx.mutiny.redi As mentioned above, the API is divided into groups: -- bitmap - `.bitmap()` - bitmap - `.bitmap()` - key (generic) - `.key()` - geo - `.geo(memberType)` @@ -282,7 +288,8 @@ As mentioned above, the API is divided into groups: - count-min - `.countmin()` (requires the https://redis.com/modules/redis-bloom/[RedisBloom] module on the server side, which also provides the count-min filter commands) - top-k - `.topk()` (requires the https://redis.com/modules/redis-bloom/[RedisBloom] module on the server side, which also provides the top-k filter commands) - graph - `.graph()` (requires the https://redis.com/modules/redis-graph/[RedisGraph] module on the server side). -These commands are marked as experimental, as we would need feedback before making them stable. +These commands are marked as experimental. +Also the module has been declared _end of life_ by https://redis.com/blog/redisgraph-eol/[Redis]. - search - `.search()` (requires the https://redis.com/modules/redis-search/[RedisSearch] module on the server side). - auto-suggest - `.autosuggest()` (requires the https://redis.com/modules/redis-search/[RedisSearch] module on the server side). - time-series - `.timeseries()` (requires the https://redis.com/modules/redis-timeseries/[Redis Time Series] module on the server side). @@ -321,7 +328,7 @@ This object has three type parameters: the type of the key, the type of the fiel <3> Use the created `commands` to associate the field `field` with the value `value` <4> Use the created `commands` to retrieve the field `field` value. -=== Serialization and Deserialization +=== Serializing and Deserializing data The data source APIs handle the serialization and deserialization automatically. By default, non-standard types are serialized into JSON and deserialized from JSON. @@ -370,7 +377,37 @@ The `canHandle` method is called to check if the codec can handle a specific typ The parameter received in the `encode` method matches that type. The object returned by the `decode` method must also match that type. -=== The `value` group +=== Use type reference + +Each group can be configured with `Class`, or with `TypeReference` objects. +`TypeReference` are useful when dealing with Java generics: + +[source,java] +---- +@ApplicationScoped +public class MyRedisService { + + private static final String MY_KEY = "my-key"; + + private final HashCommands> commands; + + public MyRedisService(RedisDataSource ds) { + commands = ds.hash(new TypeReference>(){}); + } + + public void set(String field, List value) { + commands.hset(MY_KEY, field, value); + } + + public List get(String field) { + return commands.hget(MY_KEY, field); + } +} +---- + +IMPORTANT: You cannot use type references when using transaction. This is a known limitation. + +=== Manipulate cached and binary data with the `value` group The `value` group is used to manipulate https://redis.io/docs/manual/data-types/#strings[Redis Strings]. Thus, this group is not limited to Java Strings but can be used for integers (like a counter) or binary content (like images). @@ -563,7 +600,7 @@ public static class MyCache { } ---- -==== Redis transactions +==== Use Redis transactions Redis transactions are slightly different from relational database transactions. Redis transactions are a batch of commands executed altogether. @@ -627,7 +664,7 @@ TransactionResult result = ds.withTransaction(tx -> { IMPORTANT: You cannot use the pub/sub feature from within a transaction. -==== Optimistic locking +==== Implement the optimistic locking pattern To use optimistic locking, you need to use a variant of the `withTransaction` method, allowing the execution of code before the transaction starts. In other words, it will be executed as follows: @@ -702,7 +739,7 @@ NOTE: You can also execute custom command in a transaction. On startup, you can configure the Redis client to preload data into the Redis database. -=== Load scripts +=== Configure the load scripts Specify the _load script_ you want to load using: @@ -717,7 +754,7 @@ IMPORTANT: `load-script` is a build time property than cannot be overridden at r Note that each client can have a different script, even a list of scripts. In the case of a list, the data is imported in the list order (for example, first `actors.redis`, then `movies.redis` for the `my-redis` client). -=== Load Script format +=== Write load scripts The `.redis` file follows a _one command per line_ format: @@ -750,7 +787,7 @@ INCR counter EXEC ---- -=== Configuration +=== Configure the pre-loading The data is loaded when the application starts. By default, it drops the whole database before importing. @@ -759,7 +796,7 @@ You can prevent this using `quarkus.redis.flush-before-load=false`. Also, the import process only runs if the database is empty (no key). You can force to import even if there is data using the `quarkus.redis.load-only-if-empty=false` -=== Dev/Test vs. Prod +=== Distinguish dev/test vs. prod when pre-loading As mentioned above, in dev and test modes, Quarkus tries to import data by looking for the `src/main/resources/import.redis`. This behavior is disabled in _prod_ mode, and if you want to import even in production, add: @@ -773,20 +810,12 @@ Before importing in _prod_ mode, make sure you configured `quarkus.redis.flush-b IMPORTANT: In dev mode, to reload the content of the `.redis` load scripts, you need to add: `%dev.quarkus.vertx.caching=false` -== Vert.x Redis Client +== Use the Vert.x redis client In addition to the high-level API, you can use the Vertx Redis clients directly in your code. The documentation of the Vert.x Redis Client is available on the https://vertx.io/docs/vertx-redis-client/java/[Vert.x Web Site]. -== Redis Health Check - -If you are using the `quarkus-smallrye-health` extension, `quarkus-redis` will automatically add a readiness health check to validate the connection to the Redis server. - -So when you access the `/q/health/ready` endpoint of your application you will have information about the connection validation status. - -This behavior can be disabled by setting the `quarkus.redis.health.enabled` property to `false` in your `application.properties`. - -== Programmatic Redis Hosts +== Configure Redis hosts programmatically The `RedisHostsProvider` programmatically provides redis hosts. This allows for configuration of properties like redis connection password coming from other sources. @@ -839,13 +868,21 @@ public static class MyExampleCustomizer implements RedisOptionsCustomizer { } ---- -=== Dev Services +=== Use the Redis Dev Services See xref:redis-dev-services.adoc[Redis Dev Service]. -== Redis client metrics +== Configure Redis observability + +=== Enable the health checks + +If you are using the `quarkus-smallrye-health` extension, `quarkus-redis` will automatically add a readiness health check to validate the connection to the Redis server. + +So when you access the `/q/health/ready` endpoint of your application you will have information about the connection validation status. + +This behavior can be disabled by setting the `quarkus.redis.health.enabled` property to `false` in your `application.properties`. -=== Enable metrics collection +=== Enable metrics Redis client metrics are automatically enabled when the application also uses the xref:telemetry-micrometer.adoc[`quarkus-micrometer`] extension. Micrometer collects the metrics of all the Redis clients implemented by the application. @@ -905,7 +942,7 @@ The Redis client name can be found in the _tags_. The metrics contain both the Redis connection pool metrics (`redis_pool_*`) and the metrics about the command execution (`redis_commands_*`) such as the number of command, successes, failures, and durations. -=== Disable metrics collection +=== Disable metrics To disable the Redis client metrics when `quarkus-micrometer` is used, add the following property to the application configuration: diff --git a/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java b/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java index 79ea2d1f47f1f..7ba1c30da0eed 100644 --- a/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java +++ b/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java @@ -283,7 +283,7 @@ public Uni invalidateAll() { @Override public Uni invalidateIf(Predicate predicate) { return redis.send(Request.cmd(Command.KEYS).arg(getKeyPattern())) - .map(response -> marshaller.decodeAsList(response, String.class)) + .> map(response -> marshaller.decodeAsList(response, String.class)) .chain(new Function, Uni>() { @Override public Uni apply(List listOfKeys) { diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/ReactiveRedisDataSource.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/ReactiveRedisDataSource.java index b898666b7edc5..abf6899a3382d 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/ReactiveRedisDataSource.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/ReactiveRedisDataSource.java @@ -1,8 +1,12 @@ package io.quarkus.redis.datasource; +import static io.quarkus.redis.runtime.datasource.Marshaller.STRING_TYPE_REFERENCE; + import java.util.function.BiFunction; import java.util.function.Function; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.autosuggest.ReactiveAutoSuggestCommands; import io.quarkus.redis.datasource.bitmap.ReactiveBitMapCommands; import io.quarkus.redis.datasource.bloom.ReactiveBloomCommands; @@ -165,6 +169,25 @@ Uni> withTransaction(Function ReactiveHashCommands hash(Class redisKeyType, Class fieldType, Class valueType); + /** + * Gets the object to execute commands manipulating hashes (a.k.a. {@code Map<F, V>}). + *

+ * If you want to use a hash of {@code <String -> Person>} stored using String identifier, you would use: + * {@code hash(String.class, String.class, Person.class)}. + * If you want to use a hash of {@code <String -> Person>} stored using UUID identifier, you would use: + * {@code hash(UUID.class, String.class, Person.class)}. + * + * @param redisKeyType the class of the keys + * @param fieldType the class of the fields + * @param valueType the class of the values + * @param the type of the redis key + * @param the type of the fields (map's keys) + * @param the type of the value + * @return the object to execute commands manipulating hashes (a.k.a. {@code Map<K, V>}). + */ + ReactiveHashCommands hash(TypeReference redisKeyType, TypeReference fieldType, + TypeReference valueType); + /** * Gets the object to execute commands manipulating hashes (a.k.a. {@code Map<String, V>}). *

@@ -178,6 +201,19 @@ default ReactiveHashCommands hash(Class typeOfValue) { return hash(String.class, String.class, typeOfValue); } + /** + * Gets the object to execute commands manipulating hashes (a.k.a. {@code Map<String, V>}). + *

+ * This is a shortcut on {@code hash(String.class, String.class, V)} + * + * @param typeOfValue the class of the values + * @param the type of the value + * @return the object to execute commands manipulating hashes (a.k.a. {@code Map<String, V>}). + */ + default ReactiveHashCommands hash(TypeReference typeOfValue) { + return hash(STRING_TYPE_REFERENCE, STRING_TYPE_REFERENCE, typeOfValue); + } + /** * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). *

@@ -191,6 +227,19 @@ default ReactiveHashCommands hash(Class typeOfValue) { */ ReactiveGeoCommands geo(Class redisKeyType, Class memberType); + /** + * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). + *

+ * {@code V} represents the type of the member, i.e. the localized thing. + * + * @param redisKeyType the class of the keys + * @param memberType the class of the members + * @param the type of the redis key + * @param the type of the member + * @return the object to execute geo commands. + */ + ReactiveGeoCommands geo(TypeReference redisKeyType, TypeReference memberType); + /** * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). *

@@ -204,6 +253,19 @@ default ReactiveGeoCommands geo(Class memberType) { return geo(String.class, memberType); } + /** + * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). + *

+ * {@code V} represents the type of the member, i.e. the localized thing. + * + * @param memberType the class of the members + * @param the type of the member + * @return the object to execute geo commands. + */ + default ReactiveGeoCommands geo(TypeReference memberType) { + return geo(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating keys and expiration times. * @@ -213,6 +275,15 @@ default ReactiveGeoCommands geo(Class memberType) { */ ReactiveKeyCommands key(Class redisKeyType); + /** + * Gets the object to execute commands manipulating keys and expiration times. + * + * @param redisKeyType the type of the keys + * @param the type of the key + * @return the object to execute commands manipulating keys. + */ + ReactiveKeyCommands key(TypeReference redisKeyType); + /** * Gets the object to execute commands manipulating keys and expiration times. * @@ -233,6 +304,17 @@ default ReactiveKeyCommands key() { */ ReactiveSortedSetCommands sortedSet(Class redisKeyType, Class valueType); + /** + * Gets the object to execute commands manipulating sorted sets. + * + * @param redisKeyType the type of the keys + * @param valueType the type of the value sorted in the sorted sets + * @param the type of the key + * @param the type of the value + * @return the object to manipulate sorted sets. + */ + ReactiveSortedSetCommands sortedSet(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to execute commands manipulating sorted sets. * @@ -244,6 +326,17 @@ default ReactiveSortedSetCommands sortedSet(Class valueType) { return sortedSet(String.class, valueType); } + /** + * Gets the object to execute commands manipulating sorted sets. + * + * @param valueType the type of the value sorted in the sorted sets + * @param the type of the value + * @return the object to manipulate sorted sets. + */ + default ReactiveSortedSetCommands sortedSet(TypeReference valueType) { + return sortedSet(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to execute commands manipulating stored strings. *

@@ -258,6 +351,20 @@ default ReactiveSortedSetCommands sortedSet(Class valueType) { */ ReactiveValueCommands value(Class redisKeyType, Class valueType); + /** + * Gets the object to execute commands manipulating stored strings. + *

+ * NOTE: Instead of {@code string}, this group is named {@code value} to avoid the confusion with the + * Java String type. Indeed, Redis strings can be strings, numbers, byte arrays... + * + * @param redisKeyType the type of the keys + * @param valueType the type of the value, often String, or the value are encoded/decoded using codecs. + * @param the type of the key + * @param the type of the value + * @return the object to manipulate stored strings. + */ + ReactiveValueCommands value(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to execute commands manipulating stored strings. *

@@ -272,6 +379,20 @@ default ReactiveValueCommands value(Class valueType) { return value(String.class, valueType); } + /** + * Gets the object to execute commands manipulating stored strings. + *

+ * NOTE: Instead of {@code string}, this group is named {@code value} to avoid the confusion with the + * Java String type. Indeed, Redis strings can be strings, numbers, byte arrays... + * + * @param valueType the type of the value, often String, or the value are encoded/decoded using codecs. + * @param the type of the value + * @return the object to manipulate stored strings. + */ + default ReactiveValueCommands value(TypeReference valueType) { + return value(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to execute commands manipulating stored strings. * @@ -309,6 +430,17 @@ default ReactiveStringCommands string(Class valueType) { */ ReactiveSetCommands set(Class redisKeyType, Class memberType); + /** + * Gets the object to execute commands manipulating sets. + * + * @param redisKeyType the type of the keys + * @param memberType the type of the member stored in each set + * @param the type of the key + * @param the type of the member + * @return the object to manipulate sets. + */ + ReactiveSetCommands set(TypeReference redisKeyType, TypeReference memberType); + /** * Gets the object to execute commands manipulating sets. * @@ -320,6 +452,17 @@ default ReactiveSetCommands set(Class memberType) { return set(String.class, memberType); } + /** + * Gets the object to execute commands manipulating sets. + * + * @param memberType the type of the member stored in each set + * @param the type of the member + * @return the object to manipulate sets. + */ + default ReactiveSetCommands set(TypeReference memberType) { + return set(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating lists. * @@ -342,6 +485,28 @@ default ReactiveListCommands list(Class memberType) { return list(String.class, memberType); } + /** + * Gets the object to execute commands manipulating lists. + * + * @param redisKeyType the type of the keys + * @param memberType the type of the member stored in each list + * @param the type of the key + * @param the type of the member + * @return the object to manipulate sets. + */ + ReactiveListCommands list(TypeReference redisKeyType, TypeReference memberType); + + /** + * Gets the object to execute commands manipulating lists. + * + * @param memberType the type of the member stored in each list + * @param the type of the member + * @return the object to manipulate sets. + */ + default ReactiveListCommands list(TypeReference memberType) { + return list(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating hyperloglog data structures. * @@ -353,6 +518,17 @@ default ReactiveListCommands list(Class memberType) { */ ReactiveHyperLogLogCommands hyperloglog(Class redisKeyType, Class memberType); + /** + * Gets the object to execute commands manipulating hyperloglog data structures. + * + * @param redisKeyType the type of the keys + * @param memberType the type of the member stored in the data structure + * @param the type of the key + * @param the type of the member + * @return the object to manipulate hyper log log data structures. + */ + ReactiveHyperLogLogCommands hyperloglog(TypeReference redisKeyType, TypeReference memberType); + /** * Gets the object to execute commands manipulating hyperloglog data structures. * @@ -364,6 +540,17 @@ default ReactiveHyperLogLogCommands hyperloglog(Class memberTy return hyperloglog(String.class, memberType); } + /** + * Gets the object to execute commands manipulating hyperloglog data structures. + * + * @param memberType the type of the member stored in the data structure + * @param the type of the member + * @return the object to manipulate hyper log log data structures. + */ + default ReactiveHyperLogLogCommands hyperloglog(TypeReference memberType) { + return hyperloglog(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating bitmap data structures. * @@ -373,6 +560,15 @@ default ReactiveHyperLogLogCommands hyperloglog(Class memberTy */ ReactiveBitMapCommands bitmap(Class redisKeyType); + /** + * Gets the object to execute commands manipulating bitmap data structures. + * + * @param redisKeyType the type of the keys + * @param the type of the key + * @return the object to manipulate bitmap data structures. + */ + ReactiveBitMapCommands bitmap(TypeReference redisKeyType); + /** * Gets the object to execute commands manipulating bitmap data structures. * @@ -395,6 +591,20 @@ default ReactiveBitMapCommands bitmap() { */ ReactiveStreamCommands stream(Class redisKeyType, Class fieldType, Class valueType); + /** + * Gets the object to execute commands manipulating streams. + * + * @param redisKeyType the class of the keys + * @param fieldType the class of the fields included in the message exchanged on the streams + * @param valueType the class of the values included in the message exchanged on the streams + * @param the type of the redis key + * @param the type of the fields (map's keys) + * @param the type of the value + * @return the object to execute commands manipulating streams. + */ + ReactiveStreamCommands stream(TypeReference redisKeyType, TypeReference fieldType, + TypeReference valueType); + /** * Gets the object to execute commands manipulating streams, using a string key, and string fields. * @@ -405,6 +615,16 @@ default ReactiveStreamCommands stream(Class typeOfValu return stream(String.class, String.class, typeOfValue); } + /** + * Gets the object to execute commands manipulating streams, using a string key, and string fields. + * + * @param the type of the value + * @return the object to execute commands manipulating streams. + */ + default ReactiveStreamCommands stream(TypeReference typeOfValue) { + return stream(STRING_TYPE_REFERENCE, STRING_TYPE_REFERENCE, typeOfValue); + } + /** * Gets the object to publish and receive messages. * @@ -414,6 +634,15 @@ default ReactiveStreamCommands stream(Class typeOfValu */ ReactivePubSubCommands pubsub(Class messageType); + /** + * Gets the object to publish and receive messages. + * + * @param messageType the type of message + * @param the type of message + * @return the object to publish and subscribe to Redis channels + */ + ReactivePubSubCommands pubsub(TypeReference messageType); + /** * Gets the object to manipulate JSON values. * This group requires the RedisJSON module. @@ -433,6 +662,15 @@ default ReactiveJsonCommands json() { */ ReactiveJsonCommands json(Class redisKeyType); + /** + * Gets the object to manipulate JSON values. + * This group requires the RedisJSON module. + * + * @param the type of keys + * @return the object to manipulate JSON values. + */ + ReactiveJsonCommands json(TypeReference redisKeyType); + /** * Gets the object to manipulate Bloom filters. * This group requires the RedisBloom module. @@ -444,6 +682,17 @@ default ReactiveBloomCommands bloom(Class valueType) { return bloom(String.class, valueType); } + /** + * Gets the object to manipulate Bloom filters. + * This group requires the RedisBloom module. + * + * @param the type of the values added into the Bloom filter + * @return the object to manipulate bloom values. + */ + default ReactiveBloomCommands bloom(TypeReference valueType) { + return bloom(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Bloom filters. * This group requires the RedisBloom module. @@ -454,6 +703,16 @@ default ReactiveBloomCommands bloom(Class valueType) { */ ReactiveBloomCommands bloom(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Bloom filters. + * This group requires the RedisBloom module. + * + * @param the type of keys + * @param the type of the values added into the Bloom filter + * @return the object to manipulate bloom values. + */ + ReactiveBloomCommands bloom(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate Cuckoo filters. * This group requires the RedisBloom module (including the Cuckoo @@ -466,6 +725,18 @@ default ReactiveCuckooCommands cuckoo(Class valueType) { return cuckoo(String.class, valueType); } + /** + * Gets the object to manipulate Cuckoo filters. + * This group requires the RedisBloom module (including the Cuckoo + * filter support). + * + * @param the type of the values added into the Cuckoo filter + * @return the object to manipulate Cuckoo values. + */ + default ReactiveCuckooCommands cuckoo(TypeReference valueType) { + return cuckoo(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Cuckoo filters. * This group requires the RedisBloom module (including the Cuckoo @@ -477,6 +748,17 @@ default ReactiveCuckooCommands cuckoo(Class valueType) { */ ReactiveCuckooCommands cuckoo(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Cuckoo filters. + * This group requires the RedisBloom module (including the Cuckoo + * filter support). + * + * @param the type of keys + * @param the type of the values added into the Cuckoo filter + * @return the object to manipulate Cuckoo values. + */ + ReactiveCuckooCommands cuckoo(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate Count-Min sketches. * This group requires the RedisBloom module (including the count-min @@ -489,6 +771,18 @@ default ReactiveCountMinCommands countmin(Class valueType) { return countmin(String.class, valueType); } + /** + * Gets the object to manipulate Count-Min sketches. + * This group requires the RedisBloom module (including the count-min + * sketches support). + * + * @param the type of the values added into the count-min sketches + * @return the object to manipulate count-min sketches. + */ + default ReactiveCountMinCommands countmin(TypeReference valueType) { + return countmin(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Count-Min sketches. * This group requires the RedisBloom module (including the count-min @@ -500,6 +794,17 @@ default ReactiveCountMinCommands countmin(Class valueType) { */ ReactiveCountMinCommands countmin(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Count-Min sketches. + * This group requires the RedisBloom module (including the count-min + * sketches support). + * + * @param the type of keys + * @param the type of the values added into the count-min sketches + * @return the object to manipulate count-min sketches. + */ + ReactiveCountMinCommands countmin(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate Top-K list. * This group requires the RedisBloom module (including the top-k @@ -512,6 +817,18 @@ default ReactiveTopKCommands topk(Class valueType) { return topk(String.class, valueType); } + /** + * Gets the object to manipulate Top-K list. + * This group requires the RedisBloom module (including the top-k + * list support). + * + * @param the type of the values added into the top-k lists + * @return the object to manipulate top-k lists. + */ + default ReactiveTopKCommands topk(TypeReference valueType) { + return topk(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Top-K list. * This group requires the RedisBloom module (including the top-k @@ -523,6 +840,17 @@ default ReactiveTopKCommands topk(Class valueType) { */ ReactiveTopKCommands topk(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Top-K list. + * This group requires the RedisBloom module (including the top-k + * list support). + * + * @param the type of keys + * @param the type of the values added into the top-k lists + * @return the object to manipulate top-k lists. + */ + ReactiveTopKCommands topk(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate graphs. * This group requires the RedisGraph module. @@ -550,8 +878,10 @@ default ReactiveGraphCommands graph() { * * @param the type of keys * @return the object to search documents + * @deprecated Use the variant without parameter, as the index name must be a string. */ @Experimental("The Redis search support is experimental") + @Deprecated ReactiveSearchCommands search(Class redisKeyType); /** @@ -575,6 +905,16 @@ default ReactiveSearchCommands search() { @Experimental("The Redis auto-suggest support is experimental") ReactiveAutoSuggestCommands autosuggest(Class redisKeyType); + /** + * Gets the object to emit commands from the {@code auto-suggest} group. + * This group requires the RedisSearch module. + * + * @param the type of keys + * @return the object to get suggestions + */ + @Experimental("The Redis auto-suggest support is experimental") + ReactiveAutoSuggestCommands autosuggest(TypeReference redisKeyType); + /** * Gets the object to emit commands from the {@code auto-suggest} group. * This group requires the RedisSearch module. @@ -596,6 +936,16 @@ default ReactiveAutoSuggestCommands autosuggest() { @Experimental("The Redis time series support is experimental") ReactiveTimeSeriesCommands timeseries(Class redisKeyType); + /** + * Gets the object to emit commands from the {@code time series} group. + * This group requires the Redis Time Series module. + * + * @param the type of keys + * @return the object to manipulate time series + */ + @Experimental("The Redis time series support is experimental") + ReactiveTimeSeriesCommands timeseries(TypeReference redisKeyType); + /** * Gets the object to emit commands from the {@code time series} group. * This group requires the Redis Time Series module. diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/RedisDataSource.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/RedisDataSource.java index 52d9852a9b46c..3410684cf367f 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/RedisDataSource.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/RedisDataSource.java @@ -1,9 +1,13 @@ package io.quarkus.redis.datasource; +import static io.quarkus.redis.runtime.datasource.Marshaller.STRING_TYPE_REFERENCE; + import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.autosuggest.AutoSuggestCommands; import io.quarkus.redis.datasource.bitmap.BitMapCommands; import io.quarkus.redis.datasource.bloom.BloomCommands; @@ -161,6 +165,25 @@ OptimisticLockingTransactionResult withTransaction(Function HashCommands hash(Class redisKeyType, Class typeOfField, Class typeOfValue); + /** + * Gets the object to execute commands manipulating hashes (a.k.a. {@code Map<F, V>}). + *

+ * If you want to use a hash of {@code <String -> Person>} stored using String identifier, you would use: + * {@code hash(String.class, String.class, Person.class)}. + * If you want to use a hash of {@code <String -> Person>} stored using UUID identifier, you would use: + * {@code hash(UUID.class, String.class, Person.class)}. + * + * @param redisKeyType the class of the keys + * @param typeOfField the class of the fields + * @param typeOfValue the class of the values + * @param the type of the redis key + * @param the type of the fields (map's keys) + * @param the type of the value + * @return the object to execute commands manipulating hashes (a.k.a. {@code Map<K, V>}). + */ + HashCommands hash(TypeReference redisKeyType, TypeReference typeOfField, + TypeReference typeOfValue); + /** * Gets the object to execute commands manipulating hashes (a.k.a. {@code Map<String, V>}). *

@@ -174,6 +197,19 @@ default HashCommands hash(Class typeOfValue) { return hash(String.class, String.class, typeOfValue); } + /** + * Gets the object to execute commands manipulating hashes (a.k.a. {@code Map<String, V>}). + *

+ * This is a shortcut on {@code hash(String.class, String.class, V)} + * + * @param typeOfValue the class of the values + * @param the type of the value + * @return the object to execute commands manipulating hashes (a.k.a. {@code Map<String, V>}). + */ + default HashCommands hash(TypeReference typeOfValue) { + return hash(STRING_TYPE_REFERENCE, STRING_TYPE_REFERENCE, typeOfValue); + } + /** * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). *

@@ -187,6 +223,19 @@ default HashCommands hash(Class typeOfValue) { */ GeoCommands geo(Class redisKeyType, Class memberType); + /** + * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). + *

+ * {@code V} represents the type of the member, i.e. the localized thing. + * + * @param redisKeyType the class of the keys + * @param memberType the class of the members + * @param the type of the redis key + * @param the type of the member + * @return the object to execute geo commands. + */ + GeoCommands geo(TypeReference redisKeyType, TypeReference memberType); + /** * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). *

@@ -200,6 +249,19 @@ default GeoCommands geo(Class memberType) { return geo(String.class, memberType); } + /** + * Gets the object to execute commands manipulating geo items (a.k.a. {@code {longitude, latitude, member}}). + *

+ * {@code V} represents the type of the member, i.e. the localized thing. + * + * @param memberType the class of the members + * @param the type of the member + * @return the object to execute geo commands. + */ + default GeoCommands geo(TypeReference memberType) { + return geo(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating keys and expiration times. * @@ -209,6 +271,15 @@ default GeoCommands geo(Class memberType) { */ KeyCommands key(Class redisKeyType); + /** + * Gets the object to execute commands manipulating keys and expiration times. + * + * @param redisKeyType the type of the keys + * @param the type of the key + * @return the object to execute commands manipulating keys. + */ + KeyCommands key(TypeReference redisKeyType); + /** * Gets the object to execute commands manipulating keys and expiration times. * @@ -229,6 +300,17 @@ default KeyCommands key() { */ SortedSetCommands sortedSet(Class redisKeyType, Class valueType); + /** + * Gets the object to execute commands manipulating sorted sets. + * + * @param redisKeyType the type of the keys + * @param valueType the type of the value sorted in the sorted sets + * @param the type of the key + * @param the type of the value + * @return the object to manipulate sorted sets. + */ + SortedSetCommands sortedSet(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to execute commands manipulating sorted sets. * @@ -240,6 +322,17 @@ default SortedSetCommands sortedSet(Class valueType) { return sortedSet(String.class, valueType); } + /** + * Gets the object to execute commands manipulating sorted sets. + * + * @param valueType the type of the value sorted in the sorted sets + * @param the type of the value + * @return the object to manipulate sorted sets. + */ + default SortedSetCommands sortedSet(TypeReference valueType) { + return sortedSet(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to execute commands manipulating stored strings. * @@ -255,6 +348,21 @@ default SortedSetCommands sortedSet(Class valueType) { */ ValueCommands value(Class redisKeyType, Class valueType); + /** + * Gets the object to execute commands manipulating stored strings. + * + *

+ * NOTE: Instead of {@code string}, this group is named {@code value} to avoid the confusion with the + * Java String type. Indeed, Redis strings can be strings, numbers, byte arrays... + * + * @param redisKeyType the type of the keys + * @param valueType the type of the value, often String, or the value are encoded/decoded using codecs. + * @param the type of the key + * @param the type of the value + * @return the object to manipulate stored strings. + */ + ValueCommands value(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to execute commands manipulating stored strings. * @@ -270,6 +378,21 @@ default ValueCommands value(Class valueType) { return value(String.class, valueType); } + /** + * Gets the object to execute commands manipulating stored strings. + * + *

+ * NOTE: Instead of {@code string}, this group is named {@code value} to avoid the confusion with the + * Java String type. Indeed, Redis strings can be strings, numbers, byte arrays... + * + * @param valueType the type of the value, often String, or the value are encoded/decoded using codecs. + * @param the type of the value + * @return the object to manipulate stored strings. + */ + default ValueCommands value(TypeReference valueType) { + return value(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to execute commands manipulating stored strings. * @@ -307,6 +430,17 @@ default StringCommands string(Class valueType) { */ SetCommands set(Class redisKeyType, Class memberType); + /** + * Gets the object to execute commands manipulating sets. + * + * @param redisKeyType the type of the keys + * @param memberType the type of the member stored in each set + * @param the type of the key + * @param the type of the member + * @return the object to manipulate sets. + */ + SetCommands set(TypeReference redisKeyType, TypeReference memberType); + /** * Gets the object to execute commands manipulating sets. * @@ -318,6 +452,17 @@ default SetCommands set(Class memberType) { return set(String.class, memberType); } + /** + * Gets the object to execute commands manipulating sets. + * + * @param memberType the type of the member stored in each set + * @param the type of the member + * @return the object to manipulate sets. + */ + default SetCommands set(TypeReference memberType) { + return set(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating lists. * @@ -340,6 +485,28 @@ default ListCommands list(Class memberType) { return list(String.class, memberType); } + /** + * Gets the object to execute commands manipulating lists. + * + * @param redisKeyType the type of the keys + * @param memberType the type of the member stored in each list + * @param the type of the key + * @param the type of the member + * @return the object to manipulate sets. + */ + ListCommands list(TypeReference redisKeyType, TypeReference memberType); + + /** + * Gets the object to execute commands manipulating lists. + * + * @param memberType the type of the member stored in each list + * @param the type of the member + * @return the object to manipulate sets. + */ + default ListCommands list(TypeReference memberType) { + return list(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating hyperloglog data structures. * @@ -351,6 +518,17 @@ default ListCommands list(Class memberType) { */ HyperLogLogCommands hyperloglog(Class redisKeyType, Class memberType); + /** + * Gets the object to execute commands manipulating hyperloglog data structures. + * + * @param redisKeyType the type of the keys + * @param memberType the type of the member stored in the data structure + * @param the type of the key + * @param the type of the member + * @return the object to manipulate hyper log log data structures. + */ + HyperLogLogCommands hyperloglog(TypeReference redisKeyType, TypeReference memberType); + /** * Gets the object to execute commands manipulating hyperloglog data structures. * @@ -362,6 +540,17 @@ default HyperLogLogCommands hyperloglog(Class memberType) { return hyperloglog(String.class, memberType); } + /** + * Gets the object to execute commands manipulating hyperloglog data structures. + * + * @param memberType the type of the member stored in the data structure + * @param the type of the member + * @return the object to manipulate hyper log log data structures. + */ + default HyperLogLogCommands hyperloglog(TypeReference memberType) { + return hyperloglog(STRING_TYPE_REFERENCE, memberType); + } + /** * Gets the object to execute commands manipulating bitmap data structures. * @@ -371,6 +560,15 @@ default HyperLogLogCommands hyperloglog(Class memberType) { */ BitMapCommands bitmap(Class redisKeyType); + /** + * Gets the object to execute commands manipulating bitmap data structures. + * + * @param redisKeyType the type of the keys + * @param the type of the key + * @return the object to manipulate bitmap data structures. + */ + BitMapCommands bitmap(TypeReference redisKeyType); + /** * Gets the object to execute commands manipulating bitmap data structures. * @@ -393,6 +591,20 @@ default BitMapCommands bitmap() { */ StreamCommands stream(Class redisKeyType, Class fieldType, Class valueType); + /** + * Gets the object to execute commands manipulating streams. + * + * @param redisKeyType the class of the keys + * @param fieldType the class of the fields included in the message exchanged on the streams + * @param valueType the class of the values included in the message exchanged on the streams + * @param the type of the redis key + * @param the type of the fields (map's keys) + * @param the type of the value + * @return the object to execute commands manipulating streams. + */ + StreamCommands stream(TypeReference redisKeyType, TypeReference fieldType, + TypeReference valueType); + /** * Gets the object to execute commands manipulating streams, using a string key, and string fields. * @@ -403,6 +615,16 @@ default StreamCommands stream(Class typeOfValue) { return stream(String.class, String.class, typeOfValue); } + /** + * Gets the object to execute commands manipulating streams, using a string key, and string fields. + * + * @param the type of the value + * @return the object to execute commands manipulating streams. + */ + default StreamCommands stream(TypeReference typeOfValue) { + return stream(STRING_TYPE_REFERENCE, STRING_TYPE_REFERENCE, typeOfValue); + } + /** * Gets the object to manipulate JSON values. * This group requires the RedisJSON module. @@ -422,6 +644,15 @@ default JsonCommands json() { */ JsonCommands json(Class redisKeyType); + /** + * Gets the object to manipulate JSON values. + * This group requires the RedisJSON module. + * + * @param the type of keys + * @return the object to manipulate JSON values. + */ + JsonCommands json(TypeReference redisKeyType); + /** * Gets the object to manipulate Bloom filters. * This group requires the RedisBloom module. @@ -433,6 +664,17 @@ default BloomCommands bloom(Class valueType) { return bloom(String.class, valueType); } + /** + * Gets the object to manipulate Bloom filters. + * This group requires the RedisBloom module. + * + * @param the type of the values added into the Bloom filter + * @return the object to manipulate bloom filters. + */ + default BloomCommands bloom(TypeReference valueType) { + return bloom(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Bloom filters. * This group requires the RedisBloom module. @@ -443,6 +685,16 @@ default BloomCommands bloom(Class valueType) { */ BloomCommands bloom(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Bloom filters. + * This group requires the RedisBloom module. + * + * @param the type of keys + * @param the type of the values added into the Bloom filter + * @return the object to manipulate bloom filters. + */ + BloomCommands bloom(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate Cuckoo filters. * This group requires the RedisBloom module (including the Cuckoo @@ -455,6 +707,18 @@ default CuckooCommands cuckoo(Class valueType) { return cuckoo(String.class, valueType); } + /** + * Gets the object to manipulate Cuckoo filters. + * This group requires the RedisBloom module (including the Cuckoo + * filter support). + * + * @param the type of the values added into the Cuckoo filter + * @return the object to manipulate Cuckoo filters. + */ + default CuckooCommands cuckoo(TypeReference valueType) { + return cuckoo(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Cuckoo filters. * This group requires the RedisBloom module (including the Cuckoo @@ -466,6 +730,17 @@ default CuckooCommands cuckoo(Class valueType) { */ CuckooCommands cuckoo(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Cuckoo filters. + * This group requires the RedisBloom module (including the Cuckoo + * filter support). + * + * @param the type of keys + * @param the type of the values added into the Cuckoo filter + * @return the object to manipulate Cuckoo filters. + */ + CuckooCommands cuckoo(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate Count-Min sketches. * This group requires the RedisBloom module (including the count-min @@ -478,6 +753,18 @@ default CountMinCommands countmin(Class valueType) { return countmin(String.class, valueType); } + /** + * Gets the object to manipulate Count-Min sketches. + * This group requires the RedisBloom module (including the count-min + * sketches support). + * + * @param the type of the values added into the count-min sketches + * @return the object to manipulate count-min sketches. + */ + default CountMinCommands countmin(TypeReference valueType) { + return countmin(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Count-Min sketches. * This group requires the RedisBloom module (including the count-min @@ -489,6 +776,17 @@ default CountMinCommands countmin(Class valueType) { */ CountMinCommands countmin(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Count-Min sketches. + * This group requires the RedisBloom module (including the count-min + * sketches support). + * + * @param the type of keys + * @param the type of the values added into the count-min sketches + * @return the object to manipulate count-min sketches. + */ + CountMinCommands countmin(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate Top-K list. * This group requires the RedisBloom module (including the top-k @@ -501,6 +799,18 @@ default TopKCommands topk(Class valueType) { return topk(String.class, valueType); } + /** + * Gets the object to manipulate Top-K list. + * This group requires the RedisBloom module (including the top-k + * list support). + * + * @param the type of the values added into the top-k lists + * @return the object to manipulate top-k lists. + */ + default TopKCommands topk(TypeReference valueType) { + return topk(STRING_TYPE_REFERENCE, valueType); + } + /** * Gets the object to manipulate Top-K list. * This group requires the RedisBloom module (including the top-k @@ -512,13 +822,24 @@ default TopKCommands topk(Class valueType) { */ TopKCommands topk(Class redisKeyType, Class valueType); + /** + * Gets the object to manipulate Top-K list. + * This group requires the RedisBloom module (including the top-k + * list support). + * + * @param the type of keys + * @param the type of the values added into the top-k lists + * @return the object to manipulate top-k lists. + */ + TopKCommands topk(TypeReference redisKeyType, TypeReference valueType); + /** * Gets the object to manipulate graphs. * This group requires the RedisGraph module. * * @return the object to manipulate graphs. */ - @Experimental("The Redis graph support is experimental") + @Experimental("The Redis graph support is experimental, in addition, the graph module EOL") default GraphCommands graph() { return graph(String.class); } @@ -530,7 +851,7 @@ default GraphCommands graph() { * @param the type of keys * @return the object to manipulate graphs lists. */ - @Experimental("The Redis graph support is experimental") + @Experimental("The Redis graph support is experimental, in addition, the graph module EOL") GraphCommands graph(Class redisKeyType); /** @@ -539,8 +860,10 @@ default GraphCommands graph() { * * @param the type of keys * @return the object to search documents + * @deprecated Use the variant without parameter, as the index name must be a string */ @Experimental("The Redis search support is experimental") + @Deprecated SearchCommands search(Class redisKeyType); /** @@ -564,6 +887,16 @@ default SearchCommands search() { @Experimental("The Redis auto-suggest support is experimental") AutoSuggestCommands autosuggest(Class redisKeyType); + /** + * Gets the object to emit commands from the {@code auto-suggest} group. + * This group requires the RedisSearch module. + * + * @param the type of keys + * @return the object to get suggestions + */ + @Experimental("The Redis auto-suggest support is experimental") + AutoSuggestCommands autosuggest(TypeReference redisKeyType); + /** * Gets the object to emit commands from the {@code auto-suggest} group. * This group requires the RedisSearch module. @@ -585,6 +918,16 @@ default AutoSuggestCommands autosuggest() { @Experimental("The Redis time series support is experimental") TimeSeriesCommands timeseries(Class redisKeyType); + /** + * Gets the object to emit commands from the {@code time series} group. + * This group requires the Redis Time Series module. + * + * @param the type of keys + * @return the object to manipulate time series + */ + @Experimental("The Redis time series support is experimental") + TimeSeriesCommands timeseries(TypeReference redisKeyType); + /** * Gets the object to emit commands from the {@code time series} group. * This group requires the Redis Time Series module. @@ -605,6 +948,15 @@ default TimeSeriesCommands timeseries() { */ PubSubCommands pubsub(Class messageType); + /** + * Gets the objects to publish and receive messages. + * + * @param messageType the type of message + * @param the type of message + * @return the object to publish and subscribe to Redis channels + */ + PubSubCommands pubsub(TypeReference messageType); + /** * Executes a command. * This method is used to execute commands not offered by the API. diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java index f7fc7ceb4c764..765caeb025e88 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/codecs/Codecs.java @@ -1,5 +1,6 @@ package io.quarkus.redis.datasource.codecs; +import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.List; @@ -7,8 +8,12 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Stream; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + import io.vertx.core.buffer.Buffer; import io.vertx.core.json.Json; +import io.vertx.core.json.jackson.DatabindCodec; public class Codecs { @@ -39,11 +44,24 @@ public static Codec getDefaultCodecFor(Type type) { } public static class JsonCodec implements Codec { - - private final Type clazz; + private final TypeReference type; + private final Class clazz; + private final ObjectMapper mapper; public JsonCodec(Type clazz) { - this.clazz = clazz; + if (clazz instanceof Class) { + this.clazz = (Class) clazz; + this.type = null; + } else { + this.type = new TypeReference<>() { + @Override + public Type getType() { + return clazz; + } + }; + this.clazz = null; + } + this.mapper = DatabindCodec.mapper(); } @Override @@ -58,8 +76,15 @@ public byte[] encode(Object item) { @Override public Object decode(byte[] payload) { - // TODO This would need to be revisited when we use TypeReference. - return Json.decodeValue(Buffer.buffer(payload), (Class) clazz); + try { + if (clazz != null) { + return Json.decodeValue(Buffer.buffer(payload), clazz); + } else { + return mapper.readValue(payload, type); + } + } catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractAutoSuggestCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractAutoSuggestCommands.java index e0288d5ea3fe0..fed14ae090c17 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractAutoSuggestCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractAutoSuggestCommands.java @@ -3,6 +3,8 @@ import static io.quarkus.redis.runtime.datasource.Validation.notNullOrBlank; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; + import io.quarkus.redis.datasource.autosuggest.GetArgs; import io.smallrye.mutiny.Uni; import io.vertx.mutiny.redis.client.Command; @@ -10,7 +12,7 @@ public class AbstractAutoSuggestCommands extends AbstractRedisCommands { - AbstractAutoSuggestCommands(RedisCommandExecutor redis, Class k) { + AbstractAutoSuggestCommands(RedisCommandExecutor redis, Type k) { super(redis, new Marshaller(k)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBitMapCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBitMapCommands.java index c6026a568ba26..646985313f768 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBitMapCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBitMapCommands.java @@ -4,6 +4,7 @@ import static io.quarkus.redis.runtime.datasource.Validation.notNullOrEmpty; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.List; import io.quarkus.redis.datasource.bitmap.BitFieldArgs; @@ -13,7 +14,7 @@ class AbstractBitMapCommands extends AbstractRedisCommands { - AbstractBitMapCommands(RedisCommandExecutor redis, Class k) { + AbstractBitMapCommands(RedisCommandExecutor redis, Type k) { super(redis, new Marshaller(k)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBloomCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBloomCommands.java index c9107580eff3d..80376d0a74332 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBloomCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractBloomCommands.java @@ -3,6 +3,8 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; + import io.quarkus.redis.datasource.bloom.BfInsertArgs; import io.quarkus.redis.datasource.bloom.BfReserveArgs; import io.smallrye.mutiny.Uni; @@ -11,7 +13,7 @@ class AbstractBloomCommands extends AbstractRedisCommands { - AbstractBloomCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractBloomCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCountMinCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCountMinCommands.java index 474e433fac24a..1129eb275d246 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCountMinCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCountMinCommands.java @@ -4,6 +4,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.isNotEmpty; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.List; import java.util.Map; @@ -13,7 +14,7 @@ public class AbstractCountMinCommands extends AbstractRedisCommands { - AbstractCountMinCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractCountMinCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCuckooCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCuckooCommands.java index 81a3435facc0f..030479e5e82e2 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCuckooCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractCuckooCommands.java @@ -3,6 +3,8 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; + import io.quarkus.redis.datasource.cuckoo.CfInsertArgs; import io.quarkus.redis.datasource.cuckoo.CfReserveArgs; import io.smallrye.mutiny.Uni; @@ -11,7 +13,7 @@ public class AbstractCuckooCommands extends AbstractRedisCommands { - AbstractCuckooCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractCuckooCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGeoCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGeoCommands.java index 47841954c31be..c9987c32544e8 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGeoCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGeoCommands.java @@ -7,6 +7,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.OptionalDouble; @@ -31,13 +32,13 @@ class AbstractGeoCommands extends AbstractRedisCommands { - protected final Class typeOfValue; + protected final Type typeOfValue; protected final Codec keyCodec; protected final Codec valueCodec; private static final Pattern NOISE_REMOVER_PATTERN = Pattern.compile("[^a-zA-Z0-9\\.]"); - AbstractGeoCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractGeoCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v)); this.typeOfValue = v; this.keyCodec = Codecs.getDefaultCodecFor(k); diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGraphCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGraphCommands.java index 40281d977eaa8..36d484edf7f36 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGraphCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractGraphCommands.java @@ -2,6 +2,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.time.Duration; import io.smallrye.mutiny.Uni; @@ -10,7 +11,7 @@ public class AbstractGraphCommands extends AbstractRedisCommands { - AbstractGraphCommands(RedisCommandExecutor redis, Class k) { + AbstractGraphCommands(RedisCommandExecutor redis, Type k) { super(redis, new Marshaller(k)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHashCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHashCommands.java index b656d42ec280b..f6acc5437ed6a 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHashCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHashCommands.java @@ -5,6 +5,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -16,10 +17,10 @@ class AbstractHashCommands extends AbstractRedisCommands { - protected final Class typeOfValue; - protected final Class typeOfField; + protected final Type typeOfValue; + protected final Type typeOfField; - AbstractHashCommands(RedisCommandExecutor redis, Class k, Class f, Class v) { + AbstractHashCommands(RedisCommandExecutor redis, Type k, Type f, Type v) { super(redis, new Marshaller(k, f, v)); this.typeOfField = f; this.typeOfValue = v; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHyperLogLogCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHyperLogLogCommands.java index a60ee76644f7b..11b9a6720e5d2 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHyperLogLogCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractHyperLogLogCommands.java @@ -4,13 +4,15 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; + import io.smallrye.mutiny.Uni; import io.vertx.mutiny.redis.client.Command; import io.vertx.mutiny.redis.client.Response; class AbstractHyperLogLogCommands extends AbstractRedisCommands { - AbstractHyperLogLogCommands(RedisCommandExecutor api, Class k, Class v) { + AbstractHyperLogLogCommands(RedisCommandExecutor api, Type k, Type v) { super(api, new Marshaller(k, v)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractJsonCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractJsonCommands.java index a2a31ead49674..8381d205b7ef1 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractJsonCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractJsonCommands.java @@ -4,6 +4,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -18,7 +19,7 @@ public class AbstractJsonCommands extends AbstractRedisCommands { private static final JsonSetArgs JSON_SET_DEFAULT = new JsonSetArgs(); - public AbstractJsonCommands(RedisCommandExecutor api, Class k) { + public AbstractJsonCommands(RedisCommandExecutor api, Type k) { super(api, new Marshaller(k)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractKeyCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractKeyCommands.java index f11a9c142ceba..dc7762bf71996 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractKeyCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractKeyCommands.java @@ -8,6 +8,7 @@ import static io.vertx.mutiny.redis.client.Command.EXPIRETIME; import static io.vertx.mutiny.redis.client.Command.PEXPIRETIME; +import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; @@ -24,9 +25,9 @@ class AbstractKeyCommands extends AbstractRedisCommands { - protected final Class typeOfKey; + protected final Type typeOfKey; - AbstractKeyCommands(RedisCommandExecutor redis, Class k) { + AbstractKeyCommands(RedisCommandExecutor redis, Type k) { super(redis, new Marshaller(k)); this.typeOfKey = k; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractListCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractListCommands.java index 66d25a6370237..51aa71db4f0b0 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractListCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractListCommands.java @@ -6,6 +6,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.positive; import static io.smallrye.mutiny.helpers.ParameterValidation.validate; +import java.lang.reflect.Type; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -20,15 +21,15 @@ class AbstractListCommands extends ReactiveSortable { - protected final Class typeOfValue; - protected final Class typeOfKey; + protected final Type typeOfValue; + protected final Type typeOfKey; protected static final LPosArgs DEFAULT_INSTANCE = new LPosArgs(); public static final Command LMPOP = Command.create("lmpop"); public static final Command BLMPOP = Command.create("blmpop"); - AbstractListCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractListCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v), v); this.typeOfKey = k; this.typeOfValue = v; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSearchCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSearchCommands.java index d4b7792a89ed8..7d314c9f148a9 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSearchCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSearchCommands.java @@ -7,6 +7,8 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.positive; import static io.smallrye.mutiny.helpers.ParameterValidation.positiveOrZero; +import java.lang.reflect.Type; + import io.quarkus.redis.datasource.search.AggregateArgs; import io.quarkus.redis.datasource.search.CreateArgs; import io.quarkus.redis.datasource.search.IndexedField; @@ -18,7 +20,7 @@ public class AbstractSearchCommands extends AbstractRedisCommands { - AbstractSearchCommands(RedisCommandExecutor redis, Class k) { + AbstractSearchCommands(RedisCommandExecutor redis, Type k) { super(redis, new Marshaller(k)); } @@ -84,10 +86,6 @@ Uni _ftAlter(String index, IndexedField field, boolean skipInitialScan return execute(cmd); } - Uni _ftAlter(String index, IndexedField field) { - return _ftAlter(index, field, false); - } - Uni _ftCreate(String index, CreateArgs args) { notNullOrBlank(index, "index"); nonNull(args, "args"); diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSetCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSetCommands.java index 799ac49ef64ff..6ab4e7a52b845 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSetCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSetCommands.java @@ -5,6 +5,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; import static io.smallrye.mutiny.helpers.ParameterValidation.positive; +import java.lang.reflect.Type; import java.util.List; import java.util.Set; @@ -14,11 +15,11 @@ class AbstractSetCommands extends ReactiveSortable { - protected final Class typeOfValue; + protected final Type typeOfValue; public static final Command SINTERCARD = Command.create("sintercard"); - AbstractSetCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractSetCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v), v); this.typeOfValue = v; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSortedSetCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSortedSetCommands.java index 9d74dc8722e87..ee014247dd5e0 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSortedSetCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractSortedSetCommands.java @@ -9,6 +9,7 @@ import static java.lang.Double.NEGATIVE_INFINITY; import static java.lang.Double.POSITIVE_INFINITY; +import java.lang.reflect.Type; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -32,8 +33,8 @@ class AbstractSortedSetCommands extends ReactiveSortable { - protected final Class typeOfValue; - protected final Class typeOfKey; + protected final Type typeOfValue; + protected final Type typeOfKey; protected static final ZAggregateArgs DEFAULT_INSTANCE_AGG = new ZAggregateArgs(); protected static final ZRangeArgs DEFAULT_INSTANCE_RANGE = new ZRangeArgs(); @@ -42,7 +43,7 @@ class AbstractSortedSetCommands extends ReactiveSortable { public static final Command ZMPOP = Command.create("zmpop"); public static final Command BZMPOP = Command.create("bzmpop"); - AbstractSortedSetCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractSortedSetCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v), v); this.typeOfValue = v; this.typeOfKey = k; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStreamCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStreamCommands.java index cd2a788c5d3e1..fa091c77ead49 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStreamCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStreamCommands.java @@ -6,6 +6,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -27,7 +28,7 @@ public class AbstractStreamCommands extends AbstractRedisCommands { - AbstractStreamCommands(RedisCommandExecutor redis, Class k, Class m, Class v) { + AbstractStreamCommands(RedisCommandExecutor redis, Type k, Type m, Type v) { super(redis, new Marshaller(k, m, v)); } @@ -318,7 +319,7 @@ Uni _xread(Map lastIdsPerStream, XReadArgs args) { return execute(cmd); } - private void writeStreamsAndIds(Map lastIdsPerStream, RedisCommand cmd) { + private void writeStreamsAndIds(Map lastIdsPerStream, RedisCommand cmd) { List ids = new ArrayList<>(); for (Map.Entry entry : lastIdsPerStream.entrySet()) { cmd.put(marshaller.encode(entry.getKey())); diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStringCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStringCommands.java index de857f54c512d..fd741433e0156 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStringCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractStringCommands.java @@ -6,6 +6,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.positive; import static io.smallrye.mutiny.helpers.ParameterValidation.positiveOrZero; +import java.lang.reflect.Type; import java.util.Map; import io.quarkus.redis.datasource.string.GetExArgs; @@ -16,11 +17,11 @@ class AbstractStringCommands extends AbstractRedisCommands { - protected final Class typeOfValue; + protected final Type typeOfValue; public static final Command LCS = Command.create("lcs"); - AbstractStringCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractStringCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v)); this.typeOfValue = v; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTimeSeriesCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTimeSeriesCommands.java index 7657d25eb9e10..584ccfec0eefc 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTimeSeriesCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTimeSeriesCommands.java @@ -4,6 +4,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; import static io.smallrye.mutiny.helpers.ParameterValidation.positive; +import java.lang.reflect.Type; import java.time.Duration; import io.quarkus.redis.datasource.timeseries.AddArgs; @@ -23,7 +24,7 @@ public class AbstractTimeSeriesCommands extends AbstractRedisCommands { - AbstractTimeSeriesCommands(RedisCommandExecutor redis, Class k) { + AbstractTimeSeriesCommands(RedisCommandExecutor redis, Type k) { super(redis, new Marshaller(k)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTopKCommands.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTopKCommands.java index 9db2bead835bc..0559e08269d25 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTopKCommands.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/AbstractTopKCommands.java @@ -5,6 +5,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; import static io.smallrye.mutiny.helpers.ParameterValidation.positive; +import java.lang.reflect.Type; import java.util.Map; import io.smallrye.mutiny.Uni; @@ -13,7 +14,7 @@ public class AbstractTopKCommands extends AbstractRedisCommands { - AbstractTopKCommands(RedisCommandExecutor redis, Class k, Class v) { + AbstractTopKCommands(RedisCommandExecutor redis, Type k, Type v) { super(redis, new Marshaller(k, v)); } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/BlockingRedisDataSourceImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/BlockingRedisDataSourceImpl.java index 3a54d936bd2c2..fcf3d8c05af84 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/BlockingRedisDataSourceImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/BlockingRedisDataSourceImpl.java @@ -7,6 +7,8 @@ import java.util.function.Consumer; import java.util.function.Function; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.ReactiveRedisDataSource; import io.quarkus.redis.datasource.RedisDataSource; import io.quarkus.redis.datasource.autosuggest.AutoSuggestCommands; @@ -186,21 +188,42 @@ public HashCommands hash(Class redisKeyType, Class return new BlockingHashCommandsImpl<>(this, reactive.hash(redisKeyType, typeOfField, typeOfValue), timeout); } + @Override + public HashCommands hash(TypeReference redisKeyType, TypeReference typeOfField, + TypeReference typeOfValue) { + return new BlockingHashCommandsImpl<>(this, reactive.hash(redisKeyType, typeOfField, typeOfValue), timeout); + } + @Override public GeoCommands geo(Class redisKeyType, Class memberType) { return new BlockingGeoCommandsImpl<>(this, reactive.geo(redisKeyType, memberType), timeout); } + @Override + public GeoCommands geo(TypeReference redisKeyType, TypeReference memberType) { + return new BlockingGeoCommandsImpl<>(this, reactive.geo(redisKeyType, memberType), timeout); + } + @Override public KeyCommands key(Class redisKeyType) { return new BlockingKeyCommandsImpl<>(this, reactive.key(redisKeyType), timeout); } + @Override + public KeyCommands key(TypeReference redisKeyType) { + return new BlockingKeyCommandsImpl<>(this, reactive.key(redisKeyType), timeout); + } + @Override public SortedSetCommands sortedSet(Class redisKeyType, Class valueType) { return new BlockingSortedSetCommandsImpl<>(this, reactive.sortedSet(redisKeyType, valueType), timeout); } + @Override + public SortedSetCommands sortedSet(TypeReference redisKeyType, TypeReference valueType) { + return new BlockingSortedSetCommandsImpl<>(this, reactive.sortedSet(redisKeyType, valueType), timeout); + } + @Override public StringCommands string(Class redisKeyType, Class valueType) { return new BlockingStringCommandsImpl<>(this, reactive.value(redisKeyType, valueType), timeout); @@ -211,56 +234,112 @@ public ValueCommands value(Class redisKeyType, Class valueTyp return new BlockingStringCommandsImpl<>(this, reactive.value(redisKeyType, valueType), timeout); } + @Override + public ValueCommands value(TypeReference redisKeyType, TypeReference valueType) { + return new BlockingStringCommandsImpl<>(this, reactive.value(redisKeyType, valueType), timeout); + } + @Override public SetCommands set(Class redisKeyType, Class memberType) { return new BlockingSetCommandsImpl<>(this, reactive.set(redisKeyType, memberType), timeout); } + @Override + public SetCommands set(TypeReference redisKeyType, TypeReference memberType) { + return new BlockingSetCommandsImpl<>(this, reactive.set(redisKeyType, memberType), timeout); + } + @Override public ListCommands list(Class redisKeyType, Class memberType) { return new BlockingListCommandsImpl<>(this, reactive.list(redisKeyType, memberType), timeout); } + @Override + public ListCommands list(TypeReference redisKeyType, TypeReference memberType) { + return new BlockingListCommandsImpl<>(this, reactive.list(redisKeyType, memberType), timeout); + } + @Override public HyperLogLogCommands hyperloglog(Class redisKeyType, Class memberType) { return new BlockingHyperLogLogCommandsImpl<>(this, reactive.hyperloglog(redisKeyType, memberType), timeout); } + @Override + public HyperLogLogCommands hyperloglog(TypeReference redisKeyType, TypeReference memberType) { + return new BlockingHyperLogLogCommandsImpl<>(this, reactive.hyperloglog(redisKeyType, memberType), timeout); + } + @Override public BitMapCommands bitmap(Class redisKeyType) { return new BlockingBitmapCommandsImpl<>(this, reactive.bitmap(redisKeyType), timeout); } + @Override + public BitMapCommands bitmap(TypeReference redisKeyType) { + return new BlockingBitmapCommandsImpl<>(this, reactive.bitmap(redisKeyType), timeout); + } + @Override public StreamCommands stream(Class redisKeyType, Class fieldType, Class valueType) { return new BlockingStreamCommandsImpl<>(this, reactive.stream(redisKeyType, fieldType, valueType), timeout); } + @Override + public StreamCommands stream(TypeReference redisKeyType, TypeReference fieldType, + TypeReference valueType) { + return new BlockingStreamCommandsImpl<>(this, reactive.stream(redisKeyType, fieldType, valueType), timeout); + } + @Override public JsonCommands json(Class redisKeyType) { return new BlockingJsonCommandsImpl<>(this, reactive.json(redisKeyType), timeout); } + @Override + public JsonCommands json(TypeReference redisKeyType) { + return new BlockingJsonCommandsImpl<>(this, reactive.json(redisKeyType), timeout); + } + @Override public BloomCommands bloom(Class redisKeyType, Class valueType) { return new BlockingBloomCommandsImpl<>(this, reactive.bloom(redisKeyType, valueType), timeout); } + @Override + public BloomCommands bloom(TypeReference redisKeyType, TypeReference valueType) { + return new BlockingBloomCommandsImpl<>(this, reactive.bloom(redisKeyType, valueType), timeout); + } + @Override public CuckooCommands cuckoo(Class redisKeyType, Class valueType) { return new BlockingCuckooCommandsImpl<>(this, reactive.cuckoo(redisKeyType, valueType), timeout); } + @Override + public CuckooCommands cuckoo(TypeReference redisKeyType, TypeReference valueType) { + return new BlockingCuckooCommandsImpl<>(this, reactive.cuckoo(redisKeyType, valueType), timeout); + } + @Override public CountMinCommands countmin(Class redisKeyType, Class valueType) { return new BlockingCountMinCommandsImpl<>(this, reactive.countmin(redisKeyType, valueType), timeout); } + @Override + public CountMinCommands countmin(TypeReference redisKeyType, TypeReference valueType) { + return new BlockingCountMinCommandsImpl<>(this, reactive.countmin(redisKeyType, valueType), timeout); + } + @Override public TopKCommands topk(Class redisKeyType, Class valueType) { return new BlockingTopKCommandsImpl<>(this, reactive.topk(redisKeyType, valueType), timeout); } + @Override + public TopKCommands topk(TypeReference redisKeyType, TypeReference valueType) { + return new BlockingTopKCommandsImpl<>(this, reactive.topk(redisKeyType, valueType), timeout); + } + @Override public GraphCommands graph(Class redisKeyType) { return new BlockingGraphCommandsImpl<>(this, reactive.graph(redisKeyType), timeout); @@ -276,16 +355,31 @@ public AutoSuggestCommands autosuggest(Class redisKeyType) { return new BlockingAutoSuggestCommandsImpl<>(this, reactive.autosuggest(redisKeyType), timeout); } + @Override + public AutoSuggestCommands autosuggest(TypeReference redisKeyType) { + return new BlockingAutoSuggestCommandsImpl<>(this, reactive.autosuggest(redisKeyType), timeout); + } + @Override public TimeSeriesCommands timeseries(Class redisKeyType) { return new BlockingTimeSeriesCommandsImpl<>(this, reactive.timeseries(redisKeyType), timeout); } + @Override + public TimeSeriesCommands timeseries(TypeReference redisKeyType) { + return new BlockingTimeSeriesCommandsImpl<>(this, reactive.timeseries(redisKeyType), timeout); + } + @Override public PubSubCommands pubsub(Class messageType) { return new BlockingPubSubCommandsImpl<>(this, reactive.pubsub(messageType), timeout); } + @Override + public PubSubCommands pubsub(TypeReference messageType) { + return new BlockingPubSubCommandsImpl<>(this, reactive.pubsub(messageType), timeout); + } + @Override public Response execute(String command, String... args) { return reactive.execute(command, args) diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/HScanReactiveCursorImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/HScanReactiveCursorImpl.java index 8ed29a5081888..bbcfe3f1fc7ce 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/HScanReactiveCursorImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/HScanReactiveCursorImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -14,13 +15,13 @@ public class HScanReactiveCursorImpl extends AbstractRedisCommands implements ReactiveHashScanCursor { private final byte[] key; - private final Class typeOfField; - private final Class typeOfValue; + private final Type typeOfField; + private final Type typeOfValue; private long cursor; private final List extra = new ArrayList<>(); - public HScanReactiveCursorImpl(RedisCommandExecutor redis, K key, Marshaller marshaller, Class typeOfField, - Class typeOfValue, + public HScanReactiveCursorImpl(RedisCommandExecutor redis, K key, Marshaller marshaller, Type typeOfField, + Type typeOfValue, List extra) { super(redis, marshaller); this.key = marshaller.encode(key); diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/Marshaller.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/Marshaller.java index 74bf0ca39540d..fccf13c352fdf 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/Marshaller.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/Marshaller.java @@ -3,6 +3,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; @@ -15,6 +16,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.codecs.Codec; import io.quarkus.redis.datasource.codecs.Codecs; import io.vertx.mutiny.redis.client.Response; @@ -22,24 +25,19 @@ public class Marshaller { - private static final Map, Codec> DEFAULT_CODECS; - - static { - DEFAULT_CODECS = Map.of( - String.class, Codecs.StringCodec.INSTANCE, - Integer.class, Codecs.IntegerCodec.INSTANCE, - Double.class, Codecs.DoubleCodec.INSTANCE); - } + public static final TypeReference STRING_TYPE_REFERENCE = new TypeReference() { + // Empty on purpose + }; - Map, Codec> codecs = new ConcurrentHashMap<>(); + Map codecs = new ConcurrentHashMap<>(); - public Marshaller(Class... hints) { + public Marshaller(Type... hints) { addAll(hints); } - public void addAll(Class... hints) { + public void addAll(Type... hints) { doesNotContainNull(hints, "hints"); - for (Class hint : hints) { + for (Type hint : hints) { codecs.computeIfAbsent(hint, h -> Codecs.getDefaultCodecFor(hint)); } } @@ -71,7 +69,7 @@ public final List encode(T... objects) { return result; } - Codec codec(Class clazz) { + Codec codec(Type clazz) { Codec codec = codecs.get(clazz); if (codec == null) { codec = Codecs.getDefaultCodecFor(clazz); @@ -80,7 +78,7 @@ Codec codec(Class clazz) { return codec; } - public final T decode(Class clazz, Response r) { + public final T decode(Type clazz, Response r) { if (r == null) { return null; } @@ -91,7 +89,7 @@ public final T decode(Class clazz, Response r) { } @SuppressWarnings("unchecked") - public final T decode(Class clazz, byte[] r) { + public final T decode(Type clazz, byte[] r) { if (r == null) { return null; } @@ -99,7 +97,7 @@ public final T decode(Class clazz, byte[] r) { return (T) codec.decode(r); } - public Map decodeAsMap(Response response, Class typeOfField, Class typeOfValue) { + public Map decodeAsMap(Response response, Type typeOfField, Type typeOfValue) { if (response == null || response.size() == 0) { return Collections.emptyMap(); } @@ -129,7 +127,7 @@ public Map decodeAsMap(Response response, Class typeOfField, Cla return map; } - public List decodeAsList(Response response, Class typeOfItem) { + public List decodeAsList(Response response, Type typeOfItem) { if (response == null) { return Collections.emptyList(); } @@ -155,7 +153,7 @@ public List decodeAsList(Response response, Function mapper) return list; } - public Set decodeAsSet(Response response, Class typeOfItem) { + public Set decodeAsSet(Response response, Type typeOfItem) { if (response == null) { return Collections.emptySet(); } @@ -166,7 +164,7 @@ public Set decodeAsSet(Response response, Class typeOfItem) { return set; } - final Map decodeAsOrderedMap(Response response, Class typeOfValue, F[] fields) { + final Map decodeAsOrderedMap(Response response, Type typeOfValue, F[] fields) { Iterator iterator = response.iterator(); Map map = new LinkedHashMap<>(); for (F field : fields) { diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveAutoSuggestCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveAutoSuggestCommandsImpl.java index c4c1107d30867..d1701b45a78c6 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveAutoSuggestCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveAutoSuggestCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -16,7 +17,7 @@ public class ReactiveAutoSuggestCommandsImpl extends AbstractAutoSuggestComma private final ReactiveRedisDataSource reactive; - public ReactiveAutoSuggestCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k) { + public ReactiveAutoSuggestCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k) { super(redis, k); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBitMapCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBitMapCommandsImpl.java index db5552a1d8895..e4fc7aeec2ffd 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBitMapCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBitMapCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.List; import io.quarkus.redis.datasource.ReactiveRedisCommands; @@ -14,7 +15,7 @@ public class ReactiveBitMapCommandsImpl extends AbstractBitMapCommands private final ReactiveRedisDataSource reactive; - public ReactiveBitMapCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k) { + public ReactiveBitMapCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k) { super(redis, k); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBloomCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBloomCommandsImpl.java index acdfaff04797d..ceccab38b4fdf 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBloomCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveBloomCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -15,7 +16,7 @@ public class ReactiveBloomCommandsImpl extends AbstractBloomCommands private final ReactiveRedisDataSource reactive; - public ReactiveBloomCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveBloomCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCountMinCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCountMinCommandsImpl.java index f36b8919583a5..9441b1a84a8b9 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCountMinCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCountMinCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -16,7 +17,7 @@ public class ReactiveCountMinCommandsImpl extends AbstractCountMinCommands private final ReactiveRedisDataSource reactive; - public ReactiveCountMinCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveCountMinCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCuckooCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCuckooCommandsImpl.java index 90ba51e670912..1562f411b793d 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCuckooCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveCuckooCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.List; import io.quarkus.redis.datasource.ReactiveRedisCommands; @@ -15,7 +16,7 @@ public class ReactiveCuckooCommandsImpl extends AbstractCuckooCommands k, Class v) { + public ReactiveCuckooCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveGeoCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveGeoCommandsImpl.java index ba51529f48792..f401866a59d0e 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveGeoCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveGeoCommandsImpl.java @@ -2,6 +2,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.List; import java.util.Set; @@ -24,7 +25,7 @@ public class ReactiveGeoCommandsImpl extends AbstractGeoCommands imp static final GeoAddArgs DEFAULT_INSTANCE = new GeoAddArgs(); private final ReactiveRedisDataSource reactive; - public ReactiveGeoCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveGeoCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHashCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHashCommandsImpl.java index c39ae6327d96d..11fd01643f2a8 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHashCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHashCommandsImpl.java @@ -2,6 +2,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.Collections; import java.util.List; import java.util.Map; @@ -17,7 +18,7 @@ public class ReactiveHashCommandsImpl extends AbstractHashCommands k, Class f, Class v) { + public ReactiveHashCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type f, Type v) { super(redis, k, f, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHyperLogLogCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHyperLogLogCommandsImpl.java index ee69f4339ff3d..025b74f33491a 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHyperLogLogCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveHyperLogLogCommandsImpl.java @@ -1,5 +1,7 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; + import io.quarkus.redis.datasource.ReactiveRedisDataSource; import io.quarkus.redis.datasource.hyperloglog.ReactiveHyperLogLogCommands; import io.smallrye.mutiny.Uni; @@ -10,7 +12,7 @@ public class ReactiveHyperLogLogCommandsImpl extends AbstractHyperLogLogCo private final ReactiveRedisDataSource reactive; - public ReactiveHyperLogLogCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveHyperLogLogCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveJsonCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveJsonCommandsImpl.java index 3284ddfbfb05f..df831f492c9a2 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveJsonCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveJsonCommandsImpl.java @@ -2,6 +2,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -19,7 +20,7 @@ public class ReactiveJsonCommandsImpl extends AbstractJsonCommands impleme private final ReactiveRedisDataSource reactive; - public ReactiveJsonCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k) { + public ReactiveJsonCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k) { super(redis, k); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveKeyCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveKeyCommandsImpl.java index 2be9e365cb41d..3042daff48ae7 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveKeyCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveKeyCommandsImpl.java @@ -2,6 +2,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.time.Duration; import java.time.Instant; import java.util.Collections; @@ -21,7 +22,7 @@ public class ReactiveKeyCommandsImpl extends AbstractKeyCommands implement private final ReactiveRedisDataSource reactive; - public ReactiveKeyCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k) { + public ReactiveKeyCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k) { super(redis, k); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveListCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveListCommandsImpl.java index 0e68e6e7c824b..c76570e54f6ec 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveListCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveListCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.time.Duration; import java.util.List; @@ -15,7 +16,7 @@ public class ReactiveListCommandsImpl extends AbstractListCommands i private final ReactiveRedisDataSource reactive; - public ReactiveListCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveListCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactivePubSubCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactivePubSubCommandsImpl.java index c3a935f13efde..10a92a867921d 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactivePubSubCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactivePubSubCommandsImpl.java @@ -4,6 +4,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.doesNotContainNull; import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -30,11 +31,11 @@ public class ReactivePubSubCommandsImpl extends AbstractRedisCommands implements ReactivePubSubCommands { - private final Class classOfMessage; + private final Type classOfMessage; private final Redis client; private final ReactiveRedisDataSourceImpl datasource; - public ReactivePubSubCommandsImpl(ReactiveRedisDataSourceImpl ds, Class classOfMessage) { + public ReactivePubSubCommandsImpl(ReactiveRedisDataSourceImpl ds, Type classOfMessage) { super(ds, new Marshaller(classOfMessage)); this.client = ds.redis; this.datasource = ds; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveRedisDataSourceImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveRedisDataSourceImpl.java index 4819b478e4900..0908b98ac0487 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveRedisDataSourceImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveRedisDataSourceImpl.java @@ -9,6 +9,8 @@ import java.util.function.BiFunction; import java.util.function.Function; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.ReactiveRedisDataSource; import io.quarkus.redis.datasource.autosuggest.ReactiveAutoSuggestCommands; import io.quarkus.redis.datasource.bitmap.ReactiveBitMapCommands; @@ -105,7 +107,6 @@ public Uni withTransaction(Function { ReactiveRedisDataSourceImpl singleConnectionDS = new ReactiveRedisDataSourceImpl(vertx, redis, connection); - List watched = List.of(keys); TransactionHolder th = new TransactionHolder(); return watch(connection, keys) // WATCH keys .chain(() -> connection.send(Request.cmd(Command.MULTI)) @@ -242,21 +243,42 @@ public ReactiveHashCommands hash(Class redisKeyType, Class return new ReactiveHashCommandsImpl<>(this, redisKeyType, fieldType, valueType); } + @Override + public ReactiveHashCommands hash(TypeReference redisKeyType, TypeReference fieldType, + TypeReference valueType) { + return new ReactiveHashCommandsImpl<>(this, redisKeyType.getType(), fieldType.getType(), valueType.getType()); + } + @Override public ReactiveGeoCommands geo(Class redisKeyType, Class memberType) { return new ReactiveGeoCommandsImpl<>(this, redisKeyType, memberType); } + @Override + public ReactiveGeoCommands geo(TypeReference redisKeyType, TypeReference memberType) { + return new ReactiveGeoCommandsImpl<>(this, redisKeyType.getType(), memberType.getType()); + } + @Override public ReactiveKeyCommands key(Class redisKeyType) { return new ReactiveKeyCommandsImpl<>(this, redisKeyType); } + @Override + public ReactiveKeyCommands key(TypeReference redisKeyType) { + return new ReactiveKeyCommandsImpl<>(this, redisKeyType.getType()); + } + @Override public ReactiveSortedSetCommands sortedSet(Class redisKeyType, Class valueType) { return new ReactiveSortedSetCommandsImpl<>(this, redisKeyType, valueType); } + @Override + public ReactiveSortedSetCommands sortedSet(TypeReference redisKeyType, TypeReference valueType) { + return new ReactiveSortedSetCommandsImpl<>(this, redisKeyType.getType(), valueType.getType()); + } + @Override public ReactiveStringCommands string(Class redisKeyType, Class valueType) { return new ReactiveStringCommandsImpl<>(this, redisKeyType, valueType); @@ -267,56 +289,112 @@ public ReactiveValueCommands value(Class redisKeyType, Class return new ReactiveStringCommandsImpl<>(this, redisKeyType, valueType); } + @Override + public ReactiveValueCommands value(TypeReference redisKeyType, TypeReference valueType) { + return new ReactiveStringCommandsImpl<>(this, redisKeyType.getType(), valueType.getType()); + } + @Override public ReactiveSetCommands set(Class redisKeyType, Class memberType) { return new ReactiveSetCommandsImpl<>(this, redisKeyType, memberType); } + @Override + public ReactiveSetCommands set(TypeReference redisKeyType, TypeReference memberType) { + return new ReactiveSetCommandsImpl<>(this, redisKeyType.getType(), memberType.getType()); + } + @Override public ReactiveListCommands list(Class redisKeyType, Class memberType) { return new ReactiveListCommandsImpl<>(this, redisKeyType, memberType); } + @Override + public ReactiveListCommands list(TypeReference redisKeyType, TypeReference memberType) { + return new ReactiveListCommandsImpl<>(this, redisKeyType.getType(), memberType.getType()); + } + @Override public ReactiveHyperLogLogCommands hyperloglog(Class redisKeyType, Class memberType) { return new ReactiveHyperLogLogCommandsImpl<>(this, redisKeyType, memberType); } + @Override + public ReactiveHyperLogLogCommands hyperloglog(TypeReference redisKeyType, TypeReference memberType) { + return new ReactiveHyperLogLogCommandsImpl<>(this, redisKeyType.getType(), memberType.getType()); + } + @Override public ReactiveBitMapCommands bitmap(Class redisKeyType) { return new ReactiveBitMapCommandsImpl<>(this, redisKeyType); } + @Override + public ReactiveBitMapCommands bitmap(TypeReference redisKeyType) { + return new ReactiveBitMapCommandsImpl<>(this, redisKeyType.getType()); + } + @Override public ReactiveStreamCommands stream(Class redisKeyType, Class fieldType, Class valueType) { return new ReactiveStreamCommandsImpl<>(this, redisKeyType, fieldType, valueType); } + @Override + public ReactiveStreamCommands stream(TypeReference redisKeyType, TypeReference fieldType, + TypeReference valueType) { + return new ReactiveStreamCommandsImpl<>(this, redisKeyType.getType(), fieldType.getType(), valueType.getType()); + } + @Override public ReactiveJsonCommands json(Class redisKeyType) { return new ReactiveJsonCommandsImpl<>(this, redisKeyType); } + @Override + public ReactiveJsonCommands json(TypeReference redisKeyType) { + return new ReactiveJsonCommandsImpl<>(this, redisKeyType.getType()); + } + @Override public ReactiveBloomCommands bloom(Class redisKeyType, Class valueType) { return new ReactiveBloomCommandsImpl<>(this, redisKeyType, valueType); } + @Override + public ReactiveBloomCommands bloom(TypeReference redisKeyType, TypeReference valueType) { + return new ReactiveBloomCommandsImpl<>(this, redisKeyType.getType(), valueType.getType()); + } + @Override public ReactiveCuckooCommands cuckoo(Class redisKeyType, Class valueType) { return new ReactiveCuckooCommandsImpl<>(this, redisKeyType, valueType); } + @Override + public ReactiveCuckooCommands cuckoo(TypeReference redisKeyType, TypeReference valueType) { + return new ReactiveCuckooCommandsImpl<>(this, redisKeyType.getType(), valueType.getType()); + } + @Override public ReactiveCountMinCommands countmin(Class redisKeyType, Class valueType) { return new ReactiveCountMinCommandsImpl<>(this, redisKeyType, valueType); } + @Override + public ReactiveCountMinCommands countmin(TypeReference redisKeyType, TypeReference valueType) { + return new ReactiveCountMinCommandsImpl<>(this, redisKeyType.getType(), valueType.getType()); + } + @Override public ReactiveTopKCommands topk(Class redisKeyType, Class valueType) { return new ReactiveTopKCommandsImpl<>(this, redisKeyType, valueType); } + @Override + public ReactiveTopKCommands topk(TypeReference redisKeyType, TypeReference valueType) { + return new ReactiveTopKCommandsImpl<>(this, redisKeyType.getType(), valueType.getType()); + } + @Override public ReactiveGraphCommands graph(Class redisKeyType) { return new ReactiveGraphCommandsImpl<>(this, redisKeyType); @@ -327,6 +405,11 @@ public ReactivePubSubCommands pubsub(Class messageType) { return new ReactivePubSubCommandsImpl<>(this, messageType); } + @Override + public ReactivePubSubCommands pubsub(TypeReference messageType) { + return new ReactivePubSubCommandsImpl<>(this, messageType.getType()); + } + @Override public ReactiveSearchCommands search(Class redisKeyType) { return new ReactiveSearchCommandsImpl<>(this, redisKeyType); @@ -337,11 +420,21 @@ public ReactiveAutoSuggestCommands autosuggest(Class redisKeyType) { return new ReactiveAutoSuggestCommandsImpl<>(this, redisKeyType); } + @Override + public ReactiveAutoSuggestCommands autosuggest(TypeReference redisKeyType) { + return new ReactiveAutoSuggestCommandsImpl<>(this, redisKeyType.getType()); + } + @Override public ReactiveTimeSeriesCommands timeseries(Class redisKeyType) { return new ReactiveTimeSeriesCommandsImpl<>(this, redisKeyType); } + @Override + public ReactiveTimeSeriesCommands timeseries(TypeReference redisKeyType) { + return new ReactiveTimeSeriesCommandsImpl<>(this, redisKeyType.getType()); + } + @Override public Redis getRedis() { return redis; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSearchCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSearchCommandsImpl.java index 2dbc99dd966b2..872d2a3f0a210 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSearchCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSearchCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -30,9 +31,9 @@ public class ReactiveSearchCommandsImpl extends AbstractSearchCommands implements ReactiveSearchCommands, ReactiveRedisCommands { private final ReactiveRedisDataSource reactive; - protected final Class keyType; + protected final Type keyType; - public ReactiveSearchCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k) { + public ReactiveSearchCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k) { super(redis, k); this.reactive = redis; this.keyType = k; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSetCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSetCommandsImpl.java index 2cda5ea9f5a23..4a2b0ca37af32 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSetCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSetCommandsImpl.java @@ -2,6 +2,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.Collections; import java.util.List; import java.util.Set; @@ -17,7 +18,7 @@ public class ReactiveSetCommandsImpl extends AbstractSetCommands imp private final ReactiveRedisDataSource reactive; - public ReactiveSetCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveSetCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortable.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortable.java index d571ce689b2da..ebd0cd916408d 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortable.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortable.java @@ -2,6 +2,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.util.List; import io.quarkus.redis.datasource.SortArgs; @@ -11,11 +12,11 @@ public class ReactiveSortable extends AbstractRedisCommands { - private final Class typeOfValue; + private final Type typeOfValue; private static final SortArgs DEFAULT_INSTANCE = new SortArgs(); - public ReactiveSortable(RedisCommandExecutor redis, Marshaller marshaller, Class typeOfValue) { + public ReactiveSortable(RedisCommandExecutor redis, Marshaller marshaller, Type typeOfValue) { super(redis, marshaller); this.typeOfValue = typeOfValue; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortedSetCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortedSetCommandsImpl.java index f2aa3e5dd65ab..46ad8aba555f2 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortedSetCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveSortedSetCommandsImpl.java @@ -3,6 +3,7 @@ import static io.smallrye.mutiny.helpers.ParameterValidation.nonNull; +import java.lang.reflect.Type; import java.time.Duration; import java.util.Collections; import java.util.List; @@ -27,7 +28,7 @@ public class ReactiveSortedSetCommandsImpl extends AbstractSortedSetComman private final ReactiveRedisDataSource reactive; - public ReactiveSortedSetCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveSortedSetCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStreamCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStreamCommandsImpl.java index cc0638a66ee6e..ca566c31b7dde 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStreamCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStreamCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; @@ -30,11 +31,11 @@ public class ReactiveStreamCommandsImpl extends AbstractStreamCommands< implements ReactiveStreamCommands, ReactiveRedisCommands { private final ReactiveRedisDataSource reactive; - private final Class typeOfValue; - private final Class typeOfField; - private final Class typeOfKey; + private final Type typeOfValue; + private final Type typeOfField; + private final Type typeOfKey; - public ReactiveStreamCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class f, Class v) { + public ReactiveStreamCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type f, Type v) { super(redis, k, f, v); this.typeOfKey = k; this.typeOfField = f; @@ -97,7 +98,7 @@ protected List> decodeMessageListPrefixedByKey(Response r if (r == null) { return List.of(); } - var actualKey = marshaller.decode(typeOfKey, r.get(0)); + K actualKey = marshaller.decode(typeOfKey, r.get(0)); var listOfMessages = r.get(1); List> list = new ArrayList<>(); for (int i = 0; i < listOfMessages.size(); i++) { diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStringCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStringCommandsImpl.java index ef0df74339db3..3e96e4c0e2921 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStringCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveStringCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.Map; import io.quarkus.redis.datasource.ReactiveRedisDataSource; @@ -15,7 +16,7 @@ public class ReactiveStringCommandsImpl extends AbstractStringCommands k, Class v) { + public ReactiveStringCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.reactive = redis; } diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTimeSeriesCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTimeSeriesCommandsImpl.java index cc29f58e7fc90..a84193d9f1a54 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTimeSeriesCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTimeSeriesCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -31,9 +32,9 @@ public class ReactiveTimeSeriesCommandsImpl extends AbstractTimeSeriesCommand implements ReactiveTimeSeriesCommands, ReactiveRedisCommands { private final ReactiveRedisDataSource reactive; - protected final Class keyType; + protected final Type keyType; - public ReactiveTimeSeriesCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k) { + public ReactiveTimeSeriesCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k) { super(redis, k); this.keyType = k; this.reactive = redis; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTopKCommandsImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTopKCommandsImpl.java index b4981b47990ea..bc0026be809d6 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTopKCommandsImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactiveTopKCommandsImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -15,9 +16,9 @@ public class ReactiveTopKCommandsImpl extends AbstractTopKCommands implements ReactiveTopKCommands, ReactiveRedisCommands { private final ReactiveRedisDataSource reactive; - final Class typeOfValue; + final Type typeOfValue; - public ReactiveTopKCommandsImpl(ReactiveRedisDataSourceImpl redis, Class k, Class v) { + public ReactiveTopKCommandsImpl(ReactiveRedisDataSourceImpl redis, Type k, Type v) { super(redis, k, v); this.typeOfValue = v; this.reactive = redis; @@ -31,7 +32,7 @@ public ReactiveRedisDataSource getDataSource() { @Override public Uni topkAdd(K key, V item) { return super._topkAdd(key, item) - .map(r -> marshaller.decodeAsList(r, typeOfValue).get(0)); + .map(r -> marshaller. decodeAsList(r, typeOfValue).get(0)); } @Override @@ -43,7 +44,7 @@ public Uni> topkAdd(K key, V... items) { @Override public Uni topkIncrBy(K key, V item, int increment) { return super._topkIncrBy(key, item, increment) - .map(r -> marshaller.decodeAsList(r, typeOfValue).get(0)); + .map(r -> marshaller. decodeAsList(r, typeOfValue).get(0)); } @Override diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/SScanReactiveCursorImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/SScanReactiveCursorImpl.java index c129961aa5893..0e4112f67fb95 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/SScanReactiveCursorImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/SScanReactiveCursorImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -13,13 +14,13 @@ public class SScanReactiveCursorImpl extends AbstractRedisCommands implements ReactiveSScanCursor { private final byte[] key; - private final Class typeOfValue; + private final Type typeOfValue; private final Marshaller marshaller; private long cursor; private final List extra = new ArrayList<>(); public SScanReactiveCursorImpl(RedisCommandExecutor redis, K key, Marshaller marshaller, - Class typeOfValue, List extra) { + Type typeOfValue, List extra) { super(redis, marshaller); this.key = marshaller.encode(key); this.cursor = ReactiveCursor.INITIAL_CURSOR_ID; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ScanReactiveCursorImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ScanReactiveCursorImpl.java index 7ed11d879d716..000009a126d9d 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ScanReactiveCursorImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ScanReactiveCursorImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -12,11 +13,11 @@ public class ScanReactiveCursorImpl extends AbstractRedisCommands implements ReactiveKeyScanCursor { - private final Class typeOfKey; + private final Type typeOfKey; private long cursor; private final List extra = new ArrayList<>(); - public ScanReactiveCursorImpl(RedisCommandExecutor redis, Marshaller marshaller, Class typeOfKey, List extra) { + public ScanReactiveCursorImpl(RedisCommandExecutor redis, Marshaller marshaller, Type typeOfKey, List extra) { super(redis, marshaller); this.cursor = ReactiveCursor.INITIAL_CURSOR_ID; this.typeOfKey = typeOfKey; diff --git a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ZScanReactiveCursorImpl.java b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ZScanReactiveCursorImpl.java index 720ac7c1501b7..8810ec1ab0f31 100644 --- a/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ZScanReactiveCursorImpl.java +++ b/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ZScanReactiveCursorImpl.java @@ -1,5 +1,6 @@ package io.quarkus.redis.runtime.datasource; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -13,11 +14,11 @@ public class ZScanReactiveCursorImpl extends AbstractRedisCommands implements ReactiveZScanCursor { private final byte[] key; - private final Class typeOfValue; + private final Type typeOfValue; private long cursor; private final List extra = new ArrayList<>(); - public ZScanReactiveCursorImpl(RedisCommandExecutor redis, K key, Marshaller marshaller, Class typeOfValue, + public ZScanReactiveCursorImpl(RedisCommandExecutor redis, K key, Marshaller marshaller, Type typeOfValue, List extra) { super(redis, marshaller); this.key = marshaller.encode(key); diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/AutoSuggestCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/AutoSuggestCommandsTest.java index 03eb4506d85e0..7b4e7fd7eb1a7 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/AutoSuggestCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/AutoSuggestCommandsTest.java @@ -4,11 +4,14 @@ import static org.awaitility.Awaitility.await; import java.time.Duration; +import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.autosuggest.AutoSuggestCommands; import io.quarkus.redis.datasource.autosuggest.GetArgs; import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl; @@ -87,4 +90,58 @@ void testSuggestions() { }); } + @Test + void testSuggestionsWithTypeReference() { + var auto = ds.autosuggest(new TypeReference>() { + // Empty on purpose. + }); + + List key = List.of(Person.person0); + + assertThat(auto.ftSugAdd(key, "hello world", 1)).isEqualTo(1L); + assertThat(auto.ftSugAdd(key, "hello world", 3, true)).isEqualTo(1L); + + assertThat(auto.ftSugAdd(key, "bonjour", 3)).isEqualTo(2L); + assertThat(auto.ftSugAdd(key, "bonjourno", 1)).isEqualTo(3L); + + assertThat(auto.ftSugLen(key)).isEqualTo(3L); + assertThat(auto.ftSugDel(key, "bonjourno")).isTrue(); + assertThat(auto.ftSugDel(key, "missing")).isFalse(); + + assertThat(auto.ftSugLen(key)).isEqualTo(2L); + + assertThat(auto.ftSugAdd(key, "hell", 3)).isEqualTo(3L); + + assertThat(auto.ftSugGet(key, "hell")).hasSize(2) + .anySatisfy(s -> assertThat(s.suggestion()).isEqualTo("hell")) + .anySatisfy(s -> assertThat(s.suggestion()).isEqualTo("hello world")); + + assertThat(auto.ftSugGet(key, "hel", new GetArgs().max(1).withScores())).hasSize(1) + .anySatisfy(s -> { + assertThat(s.suggestion()).isEqualTo("hell"); + assertThat(s.score()).isGreaterThan(0.0); + }); + + assertThat(auto.ftSugAdd(key, "hill", 3)).isEqualTo(4L); + + assertThat(auto.ftSugGet(key, "hell", new GetArgs().fuzzy())).hasSize(3) + .anySatisfy(s -> assertThat(s.suggestion()).isEqualTo("hell")) + .anySatisfy(s -> assertThat(s.suggestion()).isEqualTo("hello world")) + .anySatisfy(s -> assertThat(s.suggestion()).isEqualTo("hill")); + + assertThat(auto.ftSugGet(key, "hell", new GetArgs().fuzzy().withScores())).hasSize(3) + .anySatisfy(s -> { + assertThat(s.suggestion()).isEqualTo("hell"); + assertThat(s.score()).isGreaterThan(0.0); + }) + .anySatisfy(s -> { + assertThat(s.suggestion()).isEqualTo("hello world"); + assertThat(s.score()).isGreaterThan(0.0); + }) + .anySatisfy(s -> { + assertThat(s.suggestion()).isEqualTo("hill"); + assertThat(s.score()).isGreaterThan(0.0); + }); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BitMapCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BitMapCommandsTest.java index 29c036180288f..f67048b51a2ca 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BitMapCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BitMapCommandsTest.java @@ -16,6 +16,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.bitmap.BitFieldArgs; import io.quarkus.redis.datasource.bitmap.BitMapCommands; import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl; @@ -208,4 +210,20 @@ void setbit() { assertThat(bitmap.setbit(key, 0, 1)).isEqualTo(0); assertThat(bitmap.setbit(key, 0, 0)).isEqualTo(1); } + + @Test + void bitcountWithTypeReference() { + var bitmap = ds.bitmap(new TypeReference>() { + // Empty on purpose + }); + List key = List.of("a", "b", "c"); + assertThat(bitmap.bitcount(key)).isEqualTo(0); + + bitmap.setbit(key, 0L, 1); + bitmap.setbit(key, 1L, 1); + bitmap.setbit(key, 2L, 1); + + assertThat(bitmap.bitcount(key)).isEqualTo(3); + assertThat(bitmap.bitcount(key, 3, -1)).isEqualTo(0); + } } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BloomCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BloomCommandsTest.java index 4bfc034777d61..db23fe57e9149 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BloomCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/BloomCommandsTest.java @@ -4,11 +4,14 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.Duration; +import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.bloom.BfInsertArgs; import io.quarkus.redis.datasource.bloom.BfReserveArgs; import io.quarkus.redis.datasource.bloom.BloomCommands; @@ -100,7 +103,22 @@ void bfinsert() { assertThatThrownBy(() -> bloom.bfinsert("key2", new BfInsertArgs().capacity(600000).errorRate(0.0001).nonScaling().nocreate(), luke, leia, anakin)); assertThatThrownBy(() -> bloom.bfinsert("key3", new BfInsertArgs().capacity(600000).errorRate(0.0001).expansion(1))); + } + @Test + void bloomWithTypeReference() { + var bloom = ds.bloom(new TypeReference>() { + // Empty on purpose. + }); + var l1 = List.of(Person.person1, Person.person2); + var l2 = List.of(Person.person1, Person.person3); + assertThat(bloom.bfadd(key, l1)).isTrue(); + + assertThat(bloom.bfexists(key, l1)).isTrue(); + assertThat(bloom.bfexists(key, l2)).isFalse(); + + assertThat(bloom.bfadd(key, l1)).isFalse(); + assertThat(bloom.bfadd(key, l2)).isTrue(); } } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CountMinCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CountMinCommandsTest.java index b02bbc2b8550e..70b4b75eaf83d 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CountMinCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CountMinCommandsTest.java @@ -12,6 +12,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.countmin.CountMinCommands; import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl; @@ -104,4 +106,24 @@ void mergeWithoutWeights() { assertThat(cm.cmsQuery(key, luke)).isEqualTo(5L); } + @Test + void countMinWithTypeReference() { + Person luke = new Person("luke", "skywalker"); + Person leia = new Person("leia", "ordana"); + Person anakin = new Person("anakin", "skywalker"); + + var cm = ds.countmin(new TypeReference>() { + // Empty on purpose + }); + + cm.cmsInitByDim(key, 10, 2); + assertThat(cm.cmsIncrBy(key, List.of(leia, luke), 10)).isEqualTo(10); + assertThat(cm.cmsIncrBy(key, Map.of(List.of(leia, luke), 2L, List.of(luke, anakin), 5L, List.of(anakin), 3L))) + .contains(entry(List.of(leia, luke), 12L), entry(List.of(luke, anakin), 5L), entry(List.of(anakin), 3L)) + .hasSize(3); + + assertThat(cm.cmsQuery(key, List.of(anakin))).isEqualTo(3); + assertThat(cm.cmsQuery(key, List.of(leia, luke), List.of(luke, anakin))).containsExactly(12L, 5L); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CuckooCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CuckooCommandsTest.java index a90f502ef315f..99e36fd7b0a3c 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CuckooCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/CuckooCommandsTest.java @@ -4,11 +4,14 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.Duration; +import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.cuckoo.CfInsertArgs; import io.quarkus.redis.datasource.cuckoo.CfReserveArgs; import io.quarkus.redis.datasource.cuckoo.CuckooCommands; @@ -145,4 +148,21 @@ void cfreserve() { assertThat(cuckoo.cfmexists("key3", luke, anakin, leia)).containsExactly(true, true, true); } + @Test + void cuckooWithTypeReference() { + var cuckoo = ds.cuckoo(new TypeReference>() { + // Empty on purpose. + }); + var l1 = List.of(Person.person1, Person.person2); + var l2 = List.of(Person.person1, Person.person3); + cuckoo.cfadd(key, l1); + + assertThat(cuckoo.cfexists(key, l1)).isTrue(); + assertThat(cuckoo.cfexists(key, l2)).isFalse(); + + assertThat(cuckoo.cfaddnx(key, l1)).isFalse(); + cuckoo.cfadd(key, l2); + assertThat(cuckoo.cfexists(key, l2)).isTrue(); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/GeoCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/GeoCommandsTest.java index beb076f528d75..85e3c36605fdd 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/GeoCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/GeoCommandsTest.java @@ -6,6 +6,7 @@ import java.time.Duration; import java.util.List; +import java.util.Map; import java.util.OptionalDouble; import java.util.Set; @@ -15,6 +16,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.geo.GeoAddArgs; import io.quarkus.redis.datasource.geo.GeoCommands; import io.quarkus.redis.datasource.geo.GeoItem; @@ -90,6 +93,31 @@ void geoadd() { assertThat(added).isTrue(); } + @Test + void geoaddUsingTypeReferences() { + var g = ds.geo(new TypeReference>() { + // Empty on purpose + }); + + boolean added = g.geoadd(key, 44.9396, CRUSSOL_LATITUDE, Map.of("a", Place.crussol)); + assertThat(added).isTrue(); + + added = g.geoadd(key, 44.9396, CRUSSOL_LATITUDE, Map.of("a", Place.crussol)); + assertThat(added).isFalse(); + + added = g.geoadd(key, GeoPosition.of(GRIGNAN_LONGITUDE, GRIGNAN_LATITUDE), Map.of("a", Place.grignan)); + assertThat(added).isTrue(); + + added = g.geoadd(key, GeoItem.of(Map.of("a", Place.suze), SUZE_LONGITUDE, SUZE_LATITUDE)); + assertThat(added).isTrue(); + + List>> list = g.geosearch(key, new GeoSearchArgs>() + .byRadius(60, GeoUnit.KM).fromMember(Map.of("a", Place.crussol)).ascending().withDistance()); + assertThat(list).hasSize(2); + assertThat(list.get(0).member).isEqualTo(Map.of("a", Place.crussol)); + assertThat(list.get(1).member).isEqualTo(Map.of("a", Place.grignan)); // 58 Km from crussol + } + @Test @RequiresRedis6OrHigher void geoaddWithNx() { diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HashCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HashCommandsTest.java index 1c799b2e67e24..3d09274485c92 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HashCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HashCommandsTest.java @@ -17,6 +17,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.hash.HashCommands; import io.quarkus.redis.datasource.hash.HashScanCursor; import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl; @@ -54,6 +56,34 @@ void simpleHset() { assertThat(person).isNull(); } + @Test + void HSetWithTypeReference() { + var h = ds.hash(new TypeReference>() { + // Empty on purpose. + }); + h.hset("my-hash", "l1", List.of(Person.person1, Person.person2)); + List person = h.hget("my-hash", "l1"); + assertThat(person).containsExactly(Person.person1, Person.person2); + + assertThat(h.hdel("my-hash", "l1")).isEqualTo(1); + person = h.hget("my-hash", "l1"); + assertThat(person).isNull(); + } + + @Test + void HSetWithTypeReferenceUsingMaps() { + var h = ds.hash(new TypeReference>() { + // Empty on purpose. + }); + h.hset("my-hash", "l1", Map.of("a", Person.person1, "b", Person.person2)); + Map person = h.hget("my-hash", "l1"); + assertThat(person).containsOnly(entry("a", Person.person1), entry("b", Person.person2)); + + assertThat(h.hdel("my-hash", "l1")).isEqualTo(1); + person = h.hget("my-hash", "l1"); + assertThat(person).isNull(); + } + @Test void hdel() { assertThat(hash.hdel(key, "one")).isEqualTo(0); diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HyperLogLogCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HyperLogLogCommandsTest.java index d8340f05a70ea..1658c02f95e9a 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HyperLogLogCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/HyperLogLogCommandsTest.java @@ -4,12 +4,15 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.Duration; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.hyperloglog.HyperLogLogCommands; import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl; @@ -116,4 +119,17 @@ void pfaddPfmergePfCount() { assertThat(hll.pfcount(k2)).isEqualTo(3); } + @Test + void pfaddWithTypeReference() { + String k = getKey(); + var hll = ds.hyperloglog(new TypeReference>() { + // Empty on purpose + }); + var l1 = List.of(Person.person1, Person.person2); + var l2 = List.of(Person.person3, Person.person2); + assertThat(hll.pfadd(k, l1, l2)).isTrue(); + assertThat(hll.pfadd(k, l1, l1)).isFalse(); + Assertions.assertThat(hll.pfadd(k, l1)).isFalse(); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/JsonCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/JsonCommandsTest.java index 73e68ea63ea14..2d2ef0c81d561 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/JsonCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/JsonCommandsTest.java @@ -13,6 +13,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.json.JsonCommands; import io.quarkus.redis.datasource.json.JsonSetArgs; import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl; @@ -494,7 +496,23 @@ void type() { assertThat(json.jsonType(key, "$.arr[0]")).containsExactly("integer"); assertThat(json.jsonType("empty", "$")).containsExactly("object"); assertThat(json.jsonType("empty", "$.a")).isEmpty(); + } + + @Test + public void testJsonWithTypeReference() { + var json = ds.json(new TypeReference>() { + // Empty on purpose + }); + + var key = List.of("a", "b", "c"); + json.jsonSet(key, "$", + new JsonObject().put("a", 2).put("b", 3).put("nested", new JsonObject().put("a", 4).put("b", null))); + assertThat(json.jsonGet(key, "$..b")).containsExactly(3, null); + JsonObject object = json.jsonGet(key, "..a", "$..b"); + assertThat(object).hasSize(2); + assertThat(object.getJsonArray("..a")).containsExactly(2, 4); + assertThat(object.getJsonArray("$..b")).containsExactly(3, null); } } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/KeyCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/KeyCommandsTest.java index 4c68e0fa65b57..c99ae509b5a3c 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/KeyCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/KeyCommandsTest.java @@ -17,6 +17,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.keys.CopyArgs; import io.quarkus.redis.datasource.keys.ExpireArgs; import io.quarkus.redis.datasource.keys.KeyCommands; @@ -192,6 +194,30 @@ void keys() { assertThat(k.contains("two")).isTrue(); } + @Test + void keysWithTypeReferences() { + var v = ds.value(new TypeReference>() { + // Empty on purpose + }, new TypeReference() { + // Empty on purpose + }); + var k = ds.key(new TypeReference>() { + // Empty on purpose + }); + + assertThat(k.keys("*")).isEqualTo(List.of()); + Map, Person> map = new LinkedHashMap<>(); + map.put(List.of("one"), Person.person1); + map.put(List.of("two"), Person.person2); + map.put(List.of("three"), Person.person3); + v.mset(map); + var l = k.keys("*o*"); + assertThat(l).hasSize(2); + assertThat(l.contains(List.of("one"))).isTrue(); + assertThat(l.contains(List.of("two"))).isTrue(); + assertThat(l.contains(List.of("three"))).isFalse(); + } + @Test public void move() { ds.withConnection(connection -> { diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ListCommandTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ListCommandTest.java index 5b1b983cea2cf..f4ebd437e694e 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ListCommandTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ListCommandTest.java @@ -13,6 +13,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.core.type.TypeReference; import io.quarkus.redis.datasource.list.KeyValue; import io.quarkus.redis.datasource.list.LPosArgs; @@ -356,6 +357,19 @@ void sort() { assertThat(commands.lpop("dest2", 100)).containsExactly("1", "2", "3", "4", "5", "5", "6", "7", "8", "9"); } + @Test + void testListWithTypeReference() { + var lists = ds.list(new TypeReference>() { + // Empty on purpose + }); + + var l1 = List.of(Person.person1, Person.person2); + var l2 = List.of(Person.person1, Person.person3); + + lists.rpush(key, l1, l2); + assertThat(lists.blpop(Duration.ofSeconds(1), "one", key)).isEqualTo(KeyValue.of(key, l1)); + } + @Test void testJacksonPolymorphism() { var cmd = ds.list(Animal.class); diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/PubSubCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/PubSubCommandsTest.java index 671d77483de73..38de5c949ef73 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/PubSubCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/PubSubCommandsTest.java @@ -6,6 +6,7 @@ import java.time.Duration; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -16,6 +17,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.pubsub.PubSubCommands; import io.quarkus.redis.datasource.pubsub.ReactivePubSubCommands; import io.quarkus.redis.datasource.pubsub.RedisPubSubMessage; @@ -493,4 +496,26 @@ void utf8ChannelAndContent() { awaitNoMoreActiveChannels(); } + @Test + void testPubSubWithTypeReference() { + var pubsub = ds.pubsub(new TypeReference>() { + // Empty on purpose + }); + List people = new CopyOnWriteArrayList<>(); + PubSubCommands.RedisSubscriber subscriber = pubsub.subscribe(channel, map -> people.addAll(map.values())); + + pubsub.publish(channel, Map.of("luke", new Person("luke", "skywalker"))); + + Awaitility.await().until(() -> people.size() == 1); + + pubsub.publish(channel, Map.of("leia", new Person("leia", "skywalker"))); + + Awaitility.await().until(() -> people.size() == 2); + + subscriber.unsubscribe(); + + awaitNoMoreActiveChannels(); + + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SetCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SetCommandsTest.java index 9a11440bdc311..b5d3a1d7dfafa 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SetCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SetCommandsTest.java @@ -12,6 +12,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.list.ListCommands; import io.quarkus.redis.datasource.set.SScanCursor; import io.quarkus.redis.datasource.set.SetCommands; @@ -333,4 +335,17 @@ void sort() { assertThat(listCommands.lpop("dest2", 100)).containsExactly("1", "2", "3", "4", "5", "6", "7", "8", "9"); } + @Test + void testSetWithTypeReference() { + var sets = ds.set(new TypeReference>() { + // Empty on purpose. + }); + assertThat(sets.sadd(key, List.of(person1, person2))).isEqualTo(1L); + assertThat(sets.sadd(key, List.of(person1, person2))).isEqualTo(0); + assertThat(sets.smembers(key)).isEqualTo(Set.of(List.of(person1, person2))); + assertThat(sets.sadd(key, List.of(person2, person3), List.of(person4))).isEqualTo(2); + assertThat(sets.smembers(key)).containsExactlyInAnyOrder(List.of(person1, person2), List.of(person2, person3), + List.of(person4)); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SortedSetCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SortedSetCommandsTest.java index 6f4a92d929099..b5d791247b17e 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SortedSetCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/SortedSetCommandsTest.java @@ -16,6 +16,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.list.KeyValue; import io.quarkus.redis.datasource.list.ListCommands; import io.quarkus.redis.datasource.sortedset.Range; @@ -990,4 +992,18 @@ void sort() { assertThat(listCommands.lrange("dest1", 0, -1)).containsExactly("a", "b", "e", "f"); assertThat(listCommands.lpop("dest2", 100)).containsExactly("1", "2", "3", "4", "5", "6", "7", "8", "9"); } + + @Test + void zaddWithTypeReference() { + var set = ds.sortedSet(new TypeReference>() { + // Empty on purpose + }); + assertThat(set.zadd(key, 1.0, List.of(Place.crussol, Place.suze))).isTrue(); + assertThat(set.zadd(key, 1.0, List.of(Place.crussol, Place.suze))).isFalse(); + + assertThat(set.zrange(key, 0, -1)).isEqualTo(List.of(List.of(Place.crussol, Place.suze))); + assertThat(set.zadd(key, new ScoredValue<>(List.of(Place.grignan), 2.0), new ScoredValue<>(List.of(Place.suze), 3.0))) + .isEqualTo(2); + assertThat(set.zrange(key, 0, -1)).hasSize(3); + } } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/StreamCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/StreamCommandsTest.java index c5fc3497f5142..f79c76d565da5 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/StreamCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/StreamCommandsTest.java @@ -17,6 +17,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.stream.PendingMessage; import io.quarkus.redis.datasource.stream.StreamCommands; import io.quarkus.redis.datasource.stream.StreamMessage; @@ -767,4 +769,23 @@ void xPendingExtendedTestWithIdle() { }); } + @Test + void streamWithTypeReference() { + var stream = ds.stream(new TypeReference>() { + // Empty on purpose + }); + stream.xadd("my-stream", Map.of("duration", List.of(1532), "event-id", List.of(5), "user-id", List.of(77788))); + stream.xadd("my-stream", Map.of("duration", List.of(1533), "event-id", List.of(6), "user-id", List.of(77788))); + stream.xadd("my-stream", Map.of("duration", List.of(1534), "event-id", List.of(7), "user-id", List.of(77788))); + + List>> messages = stream.xread("my-stream", "0-0"); + assertThat(messages).hasSize(3) + .allSatisfy(m -> { + assertThat(m.key()).isEqualTo("my-stream"); + assertThat(m.id()).isNotEmpty().contains("-"); + assertThat(m.payload()).contains(entry("user-id", List.of(77788))).containsKey("event-id") + .containsKey("duration"); + }); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TimeSeriesCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TimeSeriesCommandsTest.java index 12524a810764b..faa980ca8b054 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TimeSeriesCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TimeSeriesCommandsTest.java @@ -5,12 +5,15 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; +import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.timeseries.AddArgs; import io.quarkus.redis.datasource.timeseries.Aggregation; import io.quarkus.redis.datasource.timeseries.AlterArgs; @@ -549,4 +552,29 @@ void testIncrementWithCreation() { assertThat(ts.tsGet(key).timestamp()).isEqualTo(1000); } + @Test + void testTimeSeriesWithTypeReference() throws InterruptedException { + var ts = ds.timeseries(new TypeReference>() { + // Empty on purpose. + }); + var key = List.of(Person.person1, Person.person2); + var key2 = List.of(Person.person0); + ts.tsCreate(key); + ts.tsCreate(key2, new CreateArgs().setRetention(Duration.of(2678400000L, ChronoUnit.MILLIS))); + + ts.tsAlter(key2, new AlterArgs().chunkSize(1024)); + + ts.tsAdd(key, 1626434637914L, 26); + ts.tsAdd(key, 27); + + Thread.sleep(1); // Do make sure we have a different timestamp + ts.tsMAdd(SeriesSample.from(key, 51), SeriesSample.from(key, 1626434637915L, 52), SeriesSample.from(key2, 22)); + + var list = ts.tsRange(key, TimeSeriesRange.fromTimeSeries()); + assertThat(list).hasSize(4); + + list = ts.tsRange(key2, TimeSeriesRange.fromTimestampToLatest(0)); + assertThat(list).hasSize(1); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TopKCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TopKCommandsTest.java index 0f952ff6fd29c..4c13b755dc310 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TopKCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/TopKCommandsTest.java @@ -5,12 +5,15 @@ import static org.assertj.core.api.Assertions.entry; import java.time.Duration; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.topk.TopKCommands; import io.quarkus.redis.runtime.datasource.BlockingRedisDataSourceImpl; @@ -74,4 +77,37 @@ void creation() { assertThatThrownBy(() -> topk.topkReserve(key + "1", 20)); } + @Test + void topKWithTypeReference() { + var l1 = List.of(new Person("luke", "skywalker"), new Person("leia", "ordana")); + var l2 = List.of(new Person("leia", "ordana")); + var l3 = List.of(new Person("anakin", "skywalker")); + + var topk = ds.topk(new TypeReference>() { + // Empty on purpose + }); + + assertThatThrownBy(() -> topk.topkAdd(key, l1)) + .hasMessageContaining("TopK"); + + topk.topkReserve(key, 2); + assertThat(topk.topkAdd(key, l1)).isEmpty(); + assertThat(topk.topkAdd(key, l1)).isEmpty(); + assertThat(topk.topkAdd(key, l2)).isEmpty(); + assertThat(topk.topkAdd(key, l3)).contains(l2); + + assertThat(topk.topkAdd(key, l1, l1, l2, l2, l2, l1)).containsExactly(null, null, l3, null, null, null); + + assertThat(topk.topkList(key)).containsExactly(l1, l2); + assertThat(topk.topkListWithCount(key)).contains(entry(l1, 5), entry(l2, 4)); + + assertThat(topk.topkIncrBy(key, l3, 6)).contains(l2); + assertThat(topk.topkListWithCount(key)).contains(entry(l3, 7), entry(l1, 5)); + + assertThat(topk.topkIncrBy(key, Map.of(l2, 20, l1, 20))).hasSize(2); + assertThat(topk.topkQuery(key, l3)).isFalse(); + assertThat(topk.topkQuery(key, l1)).isTrue(); + assertThat(topk.topkQuery(key, l1, l2, l3)).containsExactly(true, true, false); + } + } diff --git a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ValueCommandsTest.java b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ValueCommandsTest.java index 4fab036f15263..d8b97cc798a69 100644 --- a/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ValueCommandsTest.java +++ b/extensions/redis-client/runtime/src/test/java/io/quarkus/redis/datasource/ValueCommandsTest.java @@ -7,6 +7,7 @@ import java.time.Duration; import java.time.Instant; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; @@ -15,6 +16,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.core.type.TypeReference; + import io.quarkus.redis.datasource.keys.KeyCommands; import io.quarkus.redis.datasource.value.GetExArgs; import io.quarkus.redis.datasource.value.SetArgs; @@ -297,4 +300,45 @@ void binary() { String str = cmd.get(key); assertThatThrownBy(() -> Json.decodeValue(str, byte[].class)).isInstanceOf(DecodeException.class); } + + @Test + void setWithTypeReference() { + KeyCommands keys = ds.key(String.class); + var values = ds.value(new TypeReference>() { + // Empty on purpose + }); + assertThat(values.get(key)).isNull(); + List people = List.of(Person.person1, Person.person2); + values.set(key, people); + assertThat(values.get(key)).isEqualTo(people); + + values.set(key, people, new SetArgs().px(20000)); + values.set(key, people, new SetArgs().ex(10)); + assertThat(values.get(key)).isEqualTo(people); + assertThat(keys.ttl(key)).isGreaterThanOrEqualTo(9); + + values.set(key, people, new SetArgs().ex(Duration.ofSeconds(10))); + assertThat(keys.ttl(key)).isBetween(5L, 10L); + + values.set(key, people, new SetArgs().px(Duration.ofSeconds(10))); + assertThat(keys.ttl(key)).isBetween(5L, 10L); + + values.set(key, people, new SetArgs().px(10000)); + assertThat(values.get(key)).isEqualTo(people); + assertThat(keys.ttl(key)).isGreaterThanOrEqualTo(9); + + values.set(key, people, new SetArgs().nx()); + values.set(key, people, new SetArgs().xx()); + assertThat(values.get(key)).isEqualTo(people); + + keys.del(key); + values.set(key, people, new SetArgs().nx()); + assertThat(values.get(key)).isEqualTo(people); + + keys.del(key); + + values.set(key, people, new SetArgs().px(20000).nx()); + assertThat(values.get(key)).isEqualTo(people); + assertThat(keys.ttl(key) >= 19).isTrue(); + } }