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
36 changes: 36 additions & 0 deletions local_examples/cmds_hash/NRedisStack/CmdsHashExample.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// EXAMPLE: cmds_hash
using StackExchange.Redis;
using Xunit;
using System.Linq;

namespace Doc;

Expand Down Expand Up @@ -110,5 +111,40 @@ public void Run()
// >>> Hello, World
// STEP_END
Assert.Equal("Hello, World", string.Join(", ", hValsResult));
db.KeyDelete("myhash");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key deletion is in a REMOVE section in the other examples, and the assertion above probably should be visible to users either.


// STEP_START hexpire
// Set up hash with fields
db.HashSet("myhash",
[
new("field1", "Hello"),
new("field2", "World")
]
);

// Set expiration on hash fields using raw Execute
RedisResult hexpireRes1 = db.Execute("HEXPIRE", "myhash", 10, "FIELDS", 2, "field1", "field2");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually implemented in the library now (HashFieldExpire(), etc) so the catchall Execute isn't necessary. I've found you sometimes need to nudge Augie in the right direction for C# because the API method names typically don't closely resemble the command names (other clients occasionally have trip-ups like this too).

Console.WriteLine(string.Join(", ", (RedisValue[])hexpireRes1));
// >>> 1, 1

// Check TTL of the fields using raw Execute
RedisResult hexpireRes2 = db.Execute("HTTL", "myhash", "FIELDS", 2, "field1", "field2");
RedisValue[] ttlValues = (RedisValue[])hexpireRes2;
Console.WriteLine(ttlValues.Length);
// >>> 2

// Try to set expiration on non-existent field
RedisResult hexpireRes3 = db.Execute("HEXPIRE", "myhash", 10, "FIELDS", 1, "nonexistent");
Console.WriteLine(string.Join(", ", (RedisValue[])hexpireRes3));
// >>> -2
// STEP_END

RedisValue[] expireResult1 = (RedisValue[])hexpireRes1;
RedisValue[] expireResult3 = (RedisValue[])hexpireRes3;
Assert.Equal("1, 1", string.Join(", ", expireResult1));
Assert.Equal(2, ttlValues.Length);
Assert.True(ttlValues.All(ttl => (int)ttl > 0)); // TTL should be positive
Assert.Equal("-2", string.Join(", ", expireResult3));
db.KeyDelete("myhash");
}
}
51 changes: 51 additions & 0 deletions local_examples/cmds_hash/go-redis/cmds_hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"fmt"
"sort"
"time"

"github.com/redis/go-redis/v9"
)
Expand Down Expand Up @@ -293,4 +294,54 @@ func ExampleClient_hdel() {
// 1
// 1
// 0
}

func ExampleClient_hexpire() {
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password
DB: 0, // use default DB
})

// STEP_START hexpire
// Set up hash with fields
rdb.HSet(ctx, "myhash", "field1", "Hello", "field2", "World")

// Set expiration on hash fields
res1, err := rdb.HExpire(ctx, "myhash", 10*time.Second, "field1", "field2").Result()

if err != nil {
fmt.Println(err)
}

fmt.Println(res1) // >>> [1 1]

// Check TTL of the fields
res2, err := rdb.HTTL(ctx, "myhash", "field1", "field2").Result()

if err != nil {
fmt.Println(err)
}

fmt.Println(len(res2)) // >>> 2

// Try to set expiration on non-existent field
res3, err := rdb.HExpire(ctx, "myhash", 10*time.Second, "nonexistent").Result()

if err != nil {
fmt.Println(err)
}

fmt.Println(res3) // >>> [-2]

// Clean up
rdb.Del(ctx, "myhash")
// STEP_END

// Output:
// [1 1]
// 2
// [-2]
}
32 changes: 31 additions & 1 deletion local_examples/cmds_hash/jedis/CmdsHashExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Map;
import java.util.List;
import java.util.Collections;
import java.util.Arrays;

// HIDE_START
import redis.clients.jedis.UnifiedJedis;
Expand All @@ -17,6 +18,7 @@
import static java.util.stream.Collectors.toList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

// HIDE_START
public class CmdsHashExample {
Expand Down Expand Up @@ -159,13 +161,41 @@ public void run() {
System.out.println(hValsResult2);
// >>> [Hello, World]
// STEP_END
// REMOVE_START
// REMOVE_START
// Tests for 'hvals' step.
assertEquals(2, hValsResult1);
assertEquals("[Hello, World]", hValsResult2.toString());
jedis.del("myhash");
// REMOVE_END

// STEP_START hexpire
// Set up hash with fields
Map<String, String> hExpireExampleParams = new HashMap<>();
hExpireExampleParams.put("field1", "Hello");
hExpireExampleParams.put("field2", "World");
jedis.hset("myhash", hExpireExampleParams);

// Set expiration on hash fields
List<Long> hExpireResult1 = jedis.hexpire("myhash", 10, "field1", "field2");
System.out.println(hExpireResult1); // >>> [1, 1]

// Check TTL of the fields
List<Long> hExpireResult2 = jedis.httl("myhash", "field1", "field2");
System.out.println(hExpireResult2.size()); // >>> 2

// Try to set expiration on non-existent field
List<Long> hExpireResult3 = jedis.hexpire("myhash", 10, "nonexistent");
System.out.println(hExpireResult3); // >>> [-2]
// STEP_END
// REMOVE_START
// Tests for 'hexpire' step.
assertEquals(Arrays.asList(1L, 1L), hExpireResult1);
assertEquals(2, hExpireResult2.size());
assertTrue(hExpireResult2.stream().allMatch(ttl -> ttl > 0)); // TTL should be positive
assertEquals(Arrays.asList(-2L), hExpireResult3);
jedis.del("myhash");
// REMOVE_END

// HIDE_START
jedis.close();
}
Expand Down
43 changes: 43 additions & 0 deletions local_examples/cmds_hash/lettuce-async/CmdsHashExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,49 @@ public void run() {
// REMOVE_START
asyncCommands.del("myhash").toCompletableFuture().join();
// REMOVE_END

// STEP_START hexpire
// Set up hash with fields
Map<String, String> hExpireExampleParams = new HashMap<>();
hExpireExampleParams.put("field1", "Hello");
hExpireExampleParams.put("field2", "World");

CompletableFuture<Void> hExpireExample = asyncCommands.hset("myhash", hExpireExampleParams).thenCompose(res1 -> {
// REMOVE_START
assertThat(res1).isEqualTo(2L);
// REMOVE_END
// Set expiration on hash fields
return asyncCommands.hexpire("myhash", 10, "field1", "field2");
}).thenCompose(res2 -> {
System.out.println(res2);
// >>> [1, 1]
// REMOVE_START
assertThat(res2).isEqualTo(Arrays.asList(1L, 1L));
// REMOVE_END
// Check TTL of the fields
return asyncCommands.httl("myhash", "field1", "field2");
}).thenCompose(res3 -> {
System.out.println(res3.size());
// >>> 2
// REMOVE_START
assertThat(res3.size()).isEqualTo(2);
assertThat(res3.stream().allMatch(ttl -> ttl > 0)).isTrue(); // TTL should be positive
// REMOVE_END
// Try to set expiration on non-existent field
return asyncCommands.hexpire("myhash", 10, "nonexistent");
}).thenAccept(res4 -> {
System.out.println(res4);
// >>> [-2]
// REMOVE_START
assertThat(res4).isEqualTo(Arrays.asList(-2L));
// REMOVE_END
}).toCompletableFuture();
Comment on lines +217 to +223
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works fine, but the visible code reduces to thenAccept(res4 -> { System.out.println(res4);}).... This kind of lambda would normally be shortened even further into a method reference in Java 8+ style, so in the other examples, we often have a hidden thenApply(...) for the assertions, and then use the method reference .thenAccept(System.out::println) to print the output (see the suggestion for an example). It's fine if you leave the code as it is, but I was thinking maybe you could easily add a note for Augie to follow the way we use method refs in the other examples.

Suggested change
}).thenAccept(res4 -> {
System.out.println(res4);
// >>> [-2]
// REMOVE_START
assertThat(res4).isEqualTo(Arrays.asList(-2L));
// REMOVE_END
}).toCompletableFuture();
})
// REMOVE_START
.thenApply(res4 -> {
assertThat(res4).isEqualTo(Arrays.asList(-2L));
return res;
})
// REMOVE_END
.thenAccept(System.out::println)
// >>> -2
.toCompletableFuture();

// STEP_END

hExpireExample.join();
// REMOVE_START
asyncCommands.del("myhash").toCompletableFuture().join();
// REMOVE_END
} finally {
redisClient.shutdown();
}
Expand Down
52 changes: 52 additions & 0 deletions local_examples/cmds_hash/lettuce-reactive/CmdsHashExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,58 @@ public void run() {
// REMOVE_START
reactiveCommands.del("myhash").block();
// REMOVE_END

// STEP_START hexpire
// Set up hash with fields
Map<String, String> hExpireExampleParams = new HashMap<>();
hExpireExampleParams.put("field1", "Hello");
hExpireExampleParams.put("field2", "World");

Mono<Long> hExpireExample1 = reactiveCommands.hset("myhash", hExpireExampleParams).doOnNext(result -> {
// REMOVE_START
assertThat(result).isEqualTo(2L);
// REMOVE_END
});

hExpireExample1.block();

// Set expiration on hash fields
Mono<List<Long>> hExpireExample2 = reactiveCommands.hexpire("myhash", 10, "field1", "field2").collectList().doOnNext(result -> {
System.out.println(result);
// >>> [1, 1]
// REMOVE_START
assertThat(result).isEqualTo(Arrays.asList(1L, 1L));
// REMOVE_END
});

hExpireExample2.block();

// Check TTL of the fields
Mono<List<Long>> hExpireExample3 = reactiveCommands.httl("myhash", "field1", "field2").collectList().doOnNext(result -> {
System.out.println(result.size());
// >>> 2
// REMOVE_START
assertThat(result.size()).isEqualTo(2);
assertThat(result.stream().allMatch(ttl -> ttl > 0)).isTrue(); // TTL should be positive
// REMOVE_END
});

hExpireExample3.block();

// Try to set expiration on non-existent field
Mono<List<Long>> hExpireExample4 = reactiveCommands.hexpire("myhash", 10, "nonexistent").collectList().doOnNext(result -> {
System.out.println(result);
// >>> [-2]
// REMOVE_START
assertThat(result).isEqualTo(Arrays.asList(-2L));
// REMOVE_END
});
// STEP_END

hExpireExample4.block();
// REMOVE_START
reactiveCommands.del("myhash").block();
// REMOVE_END
} finally {
redisClient.shutdown();
}
Expand Down
27 changes: 27 additions & 0 deletions local_examples/cmds_hash/node-redis/cmds-hash.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,33 @@ await client.del('myhash')
// REMOVE_END
// STEP_END

// STEP_START hexpire
// Set up hash with fields
await client.hSet('myhash', {
'field1': 'Hello',
'field2': 'World'
})

// Set expiration on hash fields
const res14 = await client.hExpire('myhash', ['field1', 'field2'], 10)
console.log(res14) // [1, 1]

// Check TTL of the fields
const res15 = await client.hTTL('myhash', ['field1', 'field2'])
console.log(res15) // [10, 10] (or close to 10)

// Try to set expiration on non-existent field
const res16 = await client.hExpire('myhash', ['nonexistent'], 10)
console.log(res16) // [-2]

// REMOVE_START
assert.deepEqual(res14, [1, 1]);
assert(res15.every(ttl => ttl > 0)); // TTL should be positive
assert.deepEqual(res16, [-2]);
await client.del('myhash')
// REMOVE_END
// STEP_END

// HIDE_START
await client.close();
// HIDE_END
28 changes: 28 additions & 0 deletions local_examples/cmds_hash/predis/CmdsHashTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,34 @@ public function testCmdsHash(): void
$this->assertEquals('OK', $hValsResult1);
$this->assertEquals(['Hello', 'World'], $hValsResult2);

// STEP_START hexpire
echo "\n--- HEXPIRE Command ---\n";
// Clean up first
$this->redis->del('myhash');
Comment on lines +126 to +128
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't usually have these extra explanatory lines in the example output (bit of Augie randomness, I guess :-) ). Also, we'd normally have the del() command and the assertions in REMOVE sections.


// Set up hash with fields
$hExpireResult1 = $this->redis->hmset('myhash', ['field1' => 'Hello', 'field2' => 'World']);
echo "HMSET myhash field1 Hello field2 World: " . ($hExpireResult1 ? 'OK' : 'FAIL') . "\n"; // >>> OK

// Set expiration on hash fields
$hExpireResult2 = $this->redis->hexpire('myhash', 10, ['field1', 'field2']);
echo "HEXPIRE myhash 10 FIELDS field1 field2: " . json_encode($hExpireResult2) . "\n"; // >>> [1,1]

// Check TTL of the fields
$hExpireResult3 = $this->redis->httl('myhash', ['field1', 'field2']);
echo "HTTL myhash FIELDS field1 field2 count: " . count($hExpireResult3) . "\n"; // >>> 2

// Try to set expiration on non-existent field
$hExpireResult4 = $this->redis->hexpire('myhash', 10, ['nonexistent']);
echo "HEXPIRE myhash 10 FIELDS nonexistent: " . json_encode($hExpireResult4) . "\n"; // >>> [-2]
// STEP_END

$this->assertEquals('OK', $hExpireResult1);
$this->assertEquals([1, 1], $hExpireResult2);
$this->assertEquals(2, count($hExpireResult3));
$this->assertTrue(array_reduce($hExpireResult3, function($carry, $ttl) { return $carry && $ttl > 0; }, true)); // TTL should be positive
$this->assertEquals([-2], $hExpireResult4);

echo "\n=== All Hash Commands Tests Passed! ===\n";
}

Expand Down
24 changes: 24 additions & 0 deletions local_examples/cmds_hash/redis-py/cmds_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,28 @@
assert res11 == [ "Hello", "World" ]
r.delete("myhash")
# REMOVE_END
# STEP_END

# STEP_START hexpire
# Set up hash with fields
r.hset("myhash", mapping={"field1": "Hello", "field2": "World"})

# Set expiration on hash fields
res12 = r.hexpire("myhash", 10, "field1", "field2")
print(res12) # >>> [1, 1]

# Check TTL of the fields
res13 = r.httl("myhash", "field1", "field2")
print(res13) # >>> [10, 10] (or close to 10)

# Try to set expiration on non-existent field
res14 = r.hexpire("myhash", 10, "nonexistent")
print(res14) # >>> [-2]

# REMOVE_START
assert res12 == [1, 1]
assert all(ttl > 0 for ttl in res13) # TTL should be positive
assert res14 == [-2]
r.delete("myhash")
# REMOVE_END
# STEP_END
Loading