Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,20 @@ default Long zInterStore(byte[] destKey, byte[]... sets) {
return zSetCommands().zInterStore(destKey, sets);
}

/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default Long zInterCard(byte[]... sets) {
return zSetCommands().zInterCard(sets);
}

/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
default Long zInterCard(long limit, byte[]... sets) {
return zSetCommands().zInterCard(limit, sets);
}

/** @deprecated in favor of {@link RedisConnection#zSetCommands()}}. */
@Override
@Deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
* @author Mark Paluch
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
* @author GyeongHoe Koo
* @see RedisCommands
*/
@NullUnmarked
Expand Down Expand Up @@ -1085,6 +1086,28 @@ default Long zInterStore(byte @NonNull [] destKey, @NonNull Aggregate aggregate,
Long zInterStore(byte @NonNull [] destKey, @NonNull Aggregate aggregate, @NonNull Weights weights,
byte @NonNull [] @NonNull... sets);

/**
* Get the number of members in the intersection of sorted {@code sets}.
*
* @param sets must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 4.0
* @see <a href="https://redis.io/commands/zintercard">Redis Documentation: ZINTERCARD</a>
*/
Long zInterCard(byte @NonNull [] @NonNull... sets);

/**
* Get the number of members in the intersection of sorted {@code sets}.
*
* @param sets must not be {@literal null}.
* @param limit the maximum cardinality to compute. If the intersection has more than {@code limit} elements,
* the computation stops and returns {@code limit}.
* @return {@literal null} when used in pipeline / transaction.
* @since 4.0
* @see <a href="https://redis.io/commands/zintercard">Redis Documentation: ZINTERCARD</a>
*/
Long zInterCard(long limit, byte @NonNull [] @NonNull... sets);

/**
* Union sorted {@code sets}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,42 @@ public Long zUnionStore(byte @NonNull [] destKey, @NonNull Aggregate aggregate,
throw new InvalidDataAccessApiUsageException("ZUNIONSTORE can only be executed when all keys map to the same slot");
}

@Override
public Long zInterCard(byte @NonNull [] @NonNull... sets) {

Assert.notNull(sets, "Sets must not be null");
Assert.noNullElements(sets, "Sets must not contain null elements");

if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {

try {
return connection.getCluster().zintercard(sets);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}

throw new InvalidDataAccessApiUsageException("ZINTERCARD can only be executed when all keys map to the same slot");
}

@Override
public Long zInterCard(long limit, byte @NonNull [] @NonNull... sets) {

Assert.notNull(sets, "Sets must not be null");
Assert.noNullElements(sets, "Sets must not contain null elements");

if (ClusterSlotHashUtil.isSameSlotForAllKeys(sets)) {

try {
return connection.getCluster().zintercard(limit, sets);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}

throw new InvalidDataAccessApiUsageException("ZINTERCARD can only be executed when all keys map to the same slot");
}

@Override
public Cursor<@NonNull Tuple> zScan(byte @NonNull [] key, @NonNull ScanOptions options) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,24 @@ public Long zUnionStore(byte @NonNull [] destKey, byte @NonNull [] @NonNull... s
return connection.invoke().just(Jedis::zunionstore, PipelineBinaryCommands::zunionstore, destKey, sets);
}

@Override
public Long zInterCard(byte @NonNull [] @NonNull... sets) {

Assert.notNull(sets, "Sets must not be null");
Assert.noNullElements(sets, "Sets must not contain null elements");

return connection.invoke().just(Jedis::zintercard, PipelineBinaryCommands::zintercard, sets);
}

@Override
public Long zInterCard(long limit, byte @NonNull [] @NonNull... sets) {

Assert.notNull(sets, "Sets must not be null");
Assert.noNullElements(sets, "Sets must not contain null elements");

return connection.invoke().just(Jedis::zintercard, PipelineBinaryCommands::zintercard, limit, sets);
}

@Override
public Cursor<@NonNull Tuple> zScan(byte @NonNull [] key, @NonNull ScanOptions options) {
return zScan(key, CursorId.initial(), options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,24 @@ public Long zUnionStore(byte @NonNull [] destKey, byte @NonNull [] @NonNull... s
return connection.invoke().just(RedisSortedSetAsyncCommands::zunionstore, destKey, sets);
}

@Override
public Long zInterCard(byte @NonNull [] @NonNull... sets) {

Assert.notNull(sets, "Sets must not be null");
Assert.noNullElements(sets, "Sets must not contain null elements");

return connection.invoke().just(RedisSortedSetAsyncCommands::zintercard, sets);
}

@Override
public Long zInterCard(long limit, byte @NonNull [] @NonNull... sets) {

Assert.notNull(sets, "Sets must not be null");
Assert.noNullElements(sets, "Sets must not contain null elements");

return connection.invoke().just(RedisSortedSetAsyncCommands::zintercard, limit, sets);
}

@Override
public Cursor<@NonNull Tuple> zScan(byte @NonNull [] key, @Nullable ScanOptions options) {
return zScan(key, CursorId.initial(), options != null ? options : ScanOptions.NONE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
* @author Shyngys Sapraliyev
* @author John Blum
* @author Gunha Hwang
* @author GyeongHoe Koo
*/
@NullUnmarked
class DefaultZSetOperations<K, V> extends AbstractOperations<K, V> implements ZSetOperations<K, V> {
Expand Down Expand Up @@ -588,6 +589,22 @@ public Long intersectAndStore(@NonNull K key, Collection<@NonNull K> otherKeys,
return execute(connection -> connection.zInterStore(rawDestKey, aggregate, weights, rawKeys));
}

@Override
public Long intersectSize(@NonNull K key, @NonNull Collection<@NonNull K> otherKeys) {

byte[][] rawKeys = rawKeys(key, otherKeys);

return execute(connection -> connection.zInterCard(rawKeys));
}

@Override
public Long intersectSize(@NonNull K key, @NonNull Collection<@NonNull K> otherKeys, long limit) {

byte[][] rawKeys = rawKeys(key, otherKeys);

return execute(connection -> connection.zInterCard(limit, rawKeys));
}

@Override
public Set<V> union(@NonNull K key, @NonNull Collection<@NonNull K> otherKeys) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* @author Andrey Shlykov
* @author Shyngys Sapraliyev
* @author Gunha Hwang
* @author GyeongHoe Koo
*/
@NullUnmarked
public interface ZSetOperations<K, V> {
Expand Down Expand Up @@ -766,6 +767,40 @@ default Long intersectAndStore(@NonNull K key, @NonNull Collection<@NonNull K> o
Long intersectAndStore(@NonNull K key, @NonNull Collection<@NonNull K> otherKeys, @NonNull K destKey,
@NonNull Aggregate aggregate, @NonNull Weights weights);

/**
* Returns numbers of members in the sorted set resulting from the intersection of the sorted sets stored at {@code key} and {@code otherKey}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @see <a href="https://redis.io/commands/zintercard">Redis Documentation: ZINTERCARD</a>
*/
default Long intersectSize(@NonNull K key, @NonNull K otherKey) {
return intersectSize(key, Collections.singleton(otherKey));
}

/**
* Returns numbers of members in the sorted set resulting from the intersection of the sorted sets stored at {@code key} and {@code otherKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @see <a href="https://redis.io/commands/zintercard">Redis Documentation: ZINTERCARD</a>
*/
Long intersectSize(@NonNull K key, @NonNull Collection<@NonNull K> otherKeys);

/**
* Returns numbers of members in the sorted set resulting from the intersection of the sorted sets stored at {@code key} and {@code otherKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param limit the maximum cardinality to compute. If the intersection has more than {@code limit} elements,
* the computation stops and returns {@code limit}.
* @return {@literal null} when used in pipeline / transaction.
* @see <a href="https://redis.io/commands/zintercard">Redis Documentation: ZINTERCARD</a>
*/
Long intersectSize(@NonNull K key, @NonNull Collection<@NonNull K> otherKeys, long limit);

/**
* Union sorted {@code sets}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -608,6 +609,55 @@ void testZsetIntersectWithAggregateWeights() {
assertThat(zSetOps.score(key1, value1)).isCloseTo(6.0, offset(0.1));
}

@Test // GH-3253
@EnabledOnCommand("ZINTERCARD")
void testZsetIntersectSize() {

K key1 = keyFactory.instance();
K key2 = keyFactory.instance();
K key3 = keyFactory.instance();

V value1 = valueFactory.instance();
V value2 = valueFactory.instance();
V value3 = valueFactory.instance();

zSetOps.add(key1, value1, 1.0);
zSetOps.add(key1, value2, 2.0);
zSetOps.add(key1, value3, 3.0);

zSetOps.add(key2, value2, 4.0);
zSetOps.add(key2, value3, 5.0);

zSetOps.add(key3, value3, 6.0);

// Test basic intersectSize
assertThat(zSetOps.intersectSize(key1, key2)).isEqualTo(2L);
assertThat(zSetOps.intersectSize(key1, Collections.singletonList(key2))).isEqualTo(2L);

// Test with 3 sets
assertThat(zSetOps.intersectSize(key1, List.of(key2, key3))).isEqualTo(1L);

// Test with limit
assertThat(zSetOps.intersectSize(key1, Collections.singletonList(key2), 1L)).isEqualTo(1L);
}

@Test // GH-3253
@EnabledOnCommand("ZINTERCARD")
void testZsetIntersectSizeEmptySet() {

K key1 = keyFactory.instance();
K key2 = keyFactory.instance();

V value1 = valueFactory.instance();
V value2 = valueFactory.instance();

zSetOps.add(key1, value1, 1.0);
zSetOps.add(key2, value2, 2.0);

// No intersection
assertThat(zSetOps.intersectSize(key1, key2)).isEqualTo(0L);
}

@Test // GH-2042
@EnabledOnCommand("ZUNION")
void testZsetUnion() {
Expand Down