Redis Streams
Introduction to Redis streams
A Redis stream is a data structure that acts like an append-only log but also implements several operations to overcome some of the limits of a typical append-only log. These include random access in O(1) time and complex consumption strategies, such as consumer groups. You can use streams to record and simultaneously syndicate events in real time. Examples of Redis stream use cases include:
- Event sourcing (e.g., tracking user actions, clicks, etc.)
- Sensor monitoring (e.g., readings from devices in the field)
- Notifications (e.g., storing a record of each user's notifications in a separate stream)
Redis generates a unique ID for each stream entry. You can use these IDs to retrieve their associated entries later or to read and process all subsequent entries in the stream. Note that because these IDs are related to time, the ones shown here may vary and will be different from the IDs you see in your own Redis instance.
Redis streams support several trimming strategies (to prevent streams from growing unbounded) and more than one consumption strategy (see XREAD, XREADGROUP, and XRANGE). Starting with Redis 8.2, the XACKDEL, XDELEX, XADD, and XTRIM commands provide fine-grained control over how stream operations interact with multiple consumer groups, simplifying the coordination of message processing across different applications.
Beginning with Redis 8.6, Redis streams support idempotent message processing (at-most-once production) to prevent duplicate entries when using at-least-once delivery patterns. This feature enables reliable message submission with automatic deduplication. See Idempotent Message Processing for more information.
Examples
-
When our racers pass a checkpoint, we add a stream entry for each racer that includes the racer's name, speed, position, and location ID:
Foundational: Add entries to a stream using XADD with auto-generated IDs (creates new entries with field-value pairs)> XADD race:france * rider Castilla speed 30.2 position 1 location_id 1 "1692632086370-0" > XADD race:france * rider Norem speed 28.8 position 3 location_id 1 "1692632094485-0" > XADD race:france * rider Prickett speed 29.7 position 2 location_id 1 "1692632102976-0"""" Code samples for Stream doc pages: https://redis.io/docs/latest/develop/data-types/streams/ """ import redis r = redis.Redis(decode_responses=True) res1 = r.xadd( "race:france", {"rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1}, ) print(res1) # >>> 1692629576966-0 res2 = r.xadd( "race:france", {"rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1}, ) print(res2) # >>> 1692629594113-0 res3 = r.xadd( "race:france", {"rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1}, ) print(res3) # >>> 1692629613374-0 res4 = r.xrange("race:france", "1691765278160-0", "+", 2) print( res4 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] res5 = r.xread(streams={"race:france": 0}, count=100, block=300) print( res5 ) # >>> [ # ['race:france', # [('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ), # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # )] # ] # ] res6 = r.xadd( "race:france", {"rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2}, ) print(res6) # >>> 1692629676124-0 res7 = r.xlen("race:france") print(res7) # >>> 4 res8 = r.xadd("race:usa", {"racer": "Castilla"}, id="0-1") print(res8) # >>> 0-1 res9 = r.xadd("race:usa", {"racer": "Norem"}, id="0-2") print(res9) # >>> 0-2 try: res10 = r.xadd("race:usa", {"racer": "Prickett"}, id="0-1") print(res10) # >>> 0-1 except redis.exceptions.ResponseError as e: print(e) # >>> WRONGID # Not yet implemented res11 = r.xrange("race:france", "-", "+") print( res11 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ), # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # ), # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res12 = r.xrange("race:france", 1692629576965, 1692629576967) print( res12 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ) # ] res13 = r.xrange("race:france", "-", "+", 2) print( res13 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] res14 = r.xrange("race:france", "(1692629594113-0", "+", 2) print( res14 ) # >>> [ # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # ), # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res15 = r.xrange("race:france", "(1692629676124-0", "+", 2) print(res15) # >>> [] res16 = r.xrevrange("race:france", "+", "-", 1) print( res16 ) # >>> [ # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res17 = r.xread(streams={"race:france": 0}, count=2) print( res17 ) # >>> [ # ['race:france', [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] # ] # ] res18 = r.xgroup_create("race:france", "france_riders", "$") print(res18) # >>> True res19 = r.xgroup_create("race:italy", "italy_riders", "$", mkstream=True) print(res19) # >>> True r.xadd("race:italy", {"rider": "Castilla"}) r.xadd("race:italy", {"rider": "Royce"}) r.xadd("race:italy", {"rider": "Sam-Bodden"}) r.xadd("race:italy", {"rider": "Prickett"}) r.xadd("race:italy", {"rider": "Norem"}) res20 = r.xreadgroup( streams={"race:italy": ">"}, consumername="Alice", groupname="italy_riders", count=1, ) print(res20) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]] res21 = r.xreadgroup( streams={"race:italy": 0}, consumername="Alice", groupname="italy_riders", count=1, ) print(res21) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]] res22 = r.xack("race:italy", "italy_riders", "1692629925771-0") print(res22) # >>> 1 res23 = r.xreadgroup( streams={"race:italy": 0}, consumername="Alice", groupname="italy_riders", count=1, ) print(res23) # >>> [['race:italy', []]] res24 = r.xreadgroup( streams={"race:italy": ">"}, consumername="Bob", groupname="italy_riders", count=2, ) print( res24 ) # >>> [ # ['race:italy', [ # ('1692629925789-0', # {'rider': 'Royce'} # ), # ('1692629925790-0', # {'rider': 'Sam-Bodden'} # ) # ] # ] # ] res25 = r.xpending("race:italy", "italy_riders") print( res25 ) # >>> { # 'pending': 2, 'min': '1692629925789-0', 'max': '1692629925790-0', # 'consumers': [{'name': 'Bob', 'pending': 2}] # } res26 = r.xpending_range("race:italy", "italy_riders", "-", "+", 10) print( res26 ) # >>> [ # { # 'message_id': '1692629925789-0', 'consumer': 'Bob', # 'time_since_delivered': 31084, 'times_delivered': 1 # }, # { # 'message_id': '1692629925790-0', 'consumer': 'Bob', # 'time_since_delivered': 31084, 'times_delivered': 1 # } # ] res27 = r.xrange("race:italy", "1692629925789-0", "1692629925789-0") print(res27) # >>> [('1692629925789-0', {'rider': 'Royce'})] res28 = r.xclaim("race:italy", "italy_riders", "Alice", 60000, ["1692629925789-0"]) print(res28) # >>> [('1692629925789-0', {'rider': 'Royce'})] res29 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "0-0", 1) print(res29) # >>> ['1692629925790-0', [('1692629925789-0', {'rider': 'Royce'})]] res30 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "(1692629925789-0", 1) print(res30) # >>> ['0-0', [('1692629925790-0', {'rider': 'Sam-Bodden'})]] res31 = r.xinfo_stream("race:italy") print( res31 ) # >>> { # 'length': 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, # 'last-generated-id': '1692629926436-0', 'groups': 1, # 'first-entry': ('1692629925771-0', {'rider': 'Castilla'}), # 'last-entry': ('1692629926436-0', {'rider': 'Norem'}) # } res32 = r.xinfo_groups("race:italy") print( res32 ) # >>> [ # { # 'name': 'italy_riders', 'consumers': 2, 'pending': 2, # 'last-delivered-id': '1692629925790-0' # } # ] res33 = r.xinfo_consumers("race:italy", "italy_riders") print( res33 ) # >>> [ # {'name': 'Alice', 'pending': 2, 'idle': 199332}, # {'name': 'Bob', 'pending': 0, 'idle': 489170} # ] r.xadd("race:italy", {"rider": "Jones"}, maxlen=2) r.xadd("race:italy", {"rider": "Wood"}, maxlen=2) r.xadd("race:italy", {"rider": "Henshaw"}, maxlen=2) res34 = r.xlen("race:italy") print(res34) # >>> 8 res35 = r.xrange("race:italy", "-", "+") print( res35 ) # >>> [ # ('1692629925771-0', {'rider': 'Castilla'}), # ('1692629925789-0', {'rider': 'Royce'}), # ('1692629925790-0', {'rider': 'Sam-Bodden'}), # ('1692629925791-0', {'rider': 'Prickett'}), # ('1692629926436-0', {'rider': 'Norem'}), # ('1692630612602-0', {'rider': 'Jones'}), # ('1692630641947-0', {'rider': 'Wood'}), # ('1692630648281-0', {'rider': 'Henshaw'}) # ] r.xadd("race:italy", {"rider": "Smith"}, maxlen=2, approximate=False) res36 = r.xrange("race:italy", "-", "+") print( res36 ) # >>> [ # ('1692630648281-0', {'rider': 'Henshaw'}), # ('1692631018238-0', {'rider': 'Smith'}) # ] res37 = r.xtrim("race:italy", maxlen=10, approximate=False) print(res37) # >>> 0 res38 = r.xtrim("race:italy", maxlen=10) print(res38) # >>> 0 res39 = r.xrange("race:italy", "-", "+") print( res39 ) # >>> [ # ('1692630648281-0', {'rider': 'Henshaw'}), # ('1692631018238-0', {'rider': 'Smith'}) # ] res40 = r.xdel("race:italy", "1692631018238-0") print(res40) # >>> 1 res41 = r.xrange("race:italy", "-", "+") print(res41) # >>> [('1692630648281-0', {'rider': 'Henshaw'})]import assert from 'assert'; import { createClient } from 'redis'; const client = await createClient(); await client.connect(); const res1 = await client.xAdd( 'race:france', '*', { 'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1' } ); console.log(res1); // >>> 1700073067968-0 N.B. actual values will differ from these examples const res2 = await client.xAdd( 'race:france', '*', { 'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1' }, ); console.log(res2); // >>> 1692629594113-0 const res3 = await client.xAdd( 'race:france', '*', { 'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1' }, ); console.log(res3); // >>> 1692629613374-0 const res4 = await client.xRange('race:france', '1691765278160-0', '+', {COUNT: 2}); console.log(res4); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] const res5 = await client.xRead({ key: 'race:france', id: '0-0' }, { COUNT: 100, BLOCK: 300 }); console.log(res5); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }] }] const res6 = await client.xAdd( 'race:france', '*', { 'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2' } ); console.log(res6); // >>> 1692629676124-0 const res7 = await client.xLen('race:france'); console.log(res7); // >>> 4 const res8 = await client.xAdd('race:usa', '0-1', { 'racer': 'Castilla' }); console.log(res8); // >>> 0-1 const res9 = await client.xAdd('race:usa', '0-2', { 'racer': 'Norem' }); console.log(res9); // >>> 0-2 try { const res10 = await client.xAdd('race:usa', '0-1', { 'racer': 'Prickett' }); console.log(res10); // >>> 0-1 } catch (error) { console.error(error); // >>> [SimpleError: ERR The ID specified in XADD is equal or smaller than the target stream top item] } const res11a = await client.xAdd('race:usa', '0-*', { racer: 'Norem' }); console.log(res11a); // >>> 0-3 const res11 = await client.xRange('race:france', '-', '+'); console.log(res11); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res12 = await client.xRange('race:france', '1692629576965', '1692629576967'); console.log(res12); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }] const res13 = await client.xRange('race:france', '-', '+', {COUNT: 2}); console.log(res13); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] const res14 = await client.xRange('race:france', '(1692629594113-0', '+', {COUNT: 2}); console.log(res14); // >>> [{ id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res15 = await client.xRange('race:france', '(1692629676124-0', '+', {COUNT: 2}); console.log(res15); // >>> [] const res16 = await client.xRevRange('race:france', '+', '-', {COUNT: 1}); console.log( res16 ); // >>> [{ id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res17 = await client.xRead({ key: 'race:france', id: '0-0' }, { COUNT: 2 }); console.log(res17); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] }] const res18 = await client.xGroupCreate('race:france', 'france_riders', '$'); console.log(res18); // >>> OK const res19 = await client.xGroupCreate('race:italy', 'italy_riders', '$', { MKSTREAM: true }); console.log(res19); // >>> OK await client.xAdd('race:italy', '*', { 'rider': 'Castilla' }); await client.xAdd('race:italy', '*', { 'rider': 'Royce' }); await client.xAdd('race:italy', '*', { 'rider': 'Sam-Bodden' }); await client.xAdd('race:italy', '*', { 'rider': 'Prickett' }); await client.xAdd('race:italy', '*', { 'rider': 'Norem' }); const res20 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '>' }, { COUNT: 1 } ); console.log(res20); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }] const res21 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '0' }, { COUNT: 1 } ); console.log(res21); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }] const res22 = await client.xAck('race:italy', 'italy_riders', '1692629925771-0') console.log(res22); // >>> 1 const res23 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '0' }, { COUNT: 1 } ); console.log(res23); // >>> [{ name: 'race:italy', messages: [] }] const res24 = await client.xReadGroup( 'italy_riders', 'Bob', { key: 'race:italy', id: '>' }, { COUNT: 2 } ); console.log(res24); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }] }] const res25 = await client.xPending('race:italy', 'italy_riders'); console.log(res25); // >>> {'pending': 2, 'firstId': '1692629925789-0', 'lastId': '1692629925790-0', 'consumers': [{'name': 'Bob', 'deliveriesCounter': 2}]} const res26 = await client.xPendingRange('race:italy', 'italy_riders', '-', '+', 10); console.log(res26); // >>> [{'id': '1692629925789-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter:': 1}, {'id': '1692629925790-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter': 1}] const res27 = await client.xRange('race:italy', '1692629925789-0', '1692629925789-0'); console.log(res27); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }] const res28 = await client.xClaim( 'race:italy', 'italy_riders', 'Alice', 60000, ['1692629925789-0'] ); console.log(res28); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }] const res29 = await client.xAutoClaim('race:italy', 'italy_riders', 'Alice', 1, '0-0', { COUNT: 1 }); console.log(res29); // >>> { nextId: '1692629925790-0', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }], deletedMessages: [] } const res30 = await client.xAutoClaim( 'race:italy', 'italy_riders', 'Alice', 1, '(1692629925789-0', { COUNT: 1 } ); console.log(res30); // >>> { nextId: '0-0', messages: [{ id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }], deletedMessages: [] } const res31 = await client.xInfoStream('race:italy'); console.log(res31); // >>> { length: 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, 'last-generated-id': '1692629926436-0', 'max-deleted-entry-id': '0-0', 'entries-added': 5, 'recorded-first-entry-id': '1692629925771-0', groups: 1, 'first-entry': { id: '1692629925771-0', message: { rider: 'Castilla' } }, 'last-entry': { id: '1692629926436-0', message: { rider: 'Norem' } } } const res32 = await client.xInfoGroups('race:italy'); console.log(res32); // >>> [{ name: 'italy_riders', consumers: 2, pending: 3, 'last-delivered-id': '1692629925790-0', 'entries-read': 3, lag: 2 }] const res33 = await client.xInfoConsumers('race:italy', 'italy_riders'); console.log(res33); // >>> [{ name: 'Alice', pending: 3, idle: 170582, inactive: 170582 }, { name: 'Bob', pending: 0, idle: 489404, inactive: 489404 }] await client.xAdd('race:italy', '*', { 'rider': 'Jones' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); await client.xAdd('race:italy', '*', { 'rider': 'Wood' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); await client.xAdd('race:italy', '*', { 'rider': 'Henshaw' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); const res34 = await client.xLen('race:italy'); console.log(res34); // >>> 8 const res35 = await client.xRange('race:italy', '-', '+'); console.log(res35); // >>> [{ id: '1692629925771-0', message: { rider: 'Castilla' } }, { id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }, { id: '1692629925791-0', message: { rider: 'Prickett' } }, { id: '1692629926436-0', message: { rider: 'Norem' } }, { id: '1692630612602-0', message: { rider: 'Jones' } }, { id: '1692630641947-0', message: { rider: 'Wood' } }, { id: '1692630648281-0', message: { rider: 'Henshaw' } }] await client.xAdd('race:italy', '*', { 'rider': 'Smith' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '=', threshold: 2 } }); const res36 = await client.xRange('race:italy', '-', '+'); console.log(res36); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }] const res37 = await client.xTrim('race:italy', 'MAXLEN', 10, { strategyModifier: '=', }); console.log(res37); // >>> 0 const res38 = await client.xTrim('race:italy', "MAXLEN", 10); console.log(res38); // >>> 0 const res39 = await client.xRange('race:italy', '-', '+'); console.log(res39); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }] const res40 = await client.xDel('race:italy', '1692631018238-0'); console.log(res40); // >>> 1 const res41 = await client.xRange('race:italy', '-', '+'); console.log(res41); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }]package io.redis.examples; import redis.clients.jedis.StreamEntryID; import redis.clients.jedis.RedisClient; public class StreamsExample { public void run() { RedisClient jedis = RedisClient.create("redis://localhost:6379"); StreamEntryID res1 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","30.2");put("position","1");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res1); // >>> 1701760582225-0 StreamEntryID res2 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Norem");put("speed","28.8");put("position","3");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res2); // >>> 1701760582225-1 StreamEntryID res3 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Prickett");put("speed","29.7");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res3); // >>> 1701760582226-0 List<StreamEntry> res4 = jedis.xrange("race:france","1701760582225-0","+",2); System.out.println(res4); // >>> [1701760841292-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701760841292-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<Map.Entry<String, List<StreamEntry>>> res5= jedis.xread(XReadParams.xReadParams().block(300).count(100),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}}); System.out.println( res5 ); // >>> [race:france=[1701761996660-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701761996661-0 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701761996661-1 {rider=Prickett, speed=29.7, location_id=1, position=2}]] StreamEntryID res6 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","29.9");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res6); // >>> 1701762285679-0 long res7 = jedis.xlen("race:france"); System.out.println(res7); // >>> 4 StreamEntryID res8 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Castilla");}},XAddParams.xAddParams().id("0-1")); System.out.println(res8); // >>> 0-1 StreamEntryID res9 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-2")); System.out.println(res9); // >>> 0-2 try { StreamEntryID res10 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Prickett");}},XAddParams.xAddParams().id("0-1")); System.out.println(res10); // >>> 0-1 } catch (JedisDataException e){ System.out.println(e); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } StreamEntryID res11 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-*")); System.out.println(res11); List<StreamEntry> res12 = jedis.xrange("race:france","-","+"); System.out.println( res12 ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<StreamEntry> res13 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000),String.valueOf(System.currentTimeMillis()+1000)); System.out.println( res13 ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<StreamEntry> res14 = jedis.xrange("race:france","-","+",2); System.out.println(res14); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<StreamEntry> res15 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000)+"-0","+",2); System.out.println(res15); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<StreamEntry> res16 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()+1000)+"-0","+",2); System.out.println(res16); // >>> [] List<StreamEntry> res17 = jedis.xrevrange("race:france","+","-",1); System.out.println(res17); // >>> [1701765218592-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<Map.Entry<String, List<StreamEntry>>> res18= jedis.xread(XReadParams.xReadParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}}); System.out.println( res18 ); // >>> [race:france=[1701765384638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701765384638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]] String res19 = jedis.xgroupCreate("race:france","france_riders",StreamEntryID.LAST_ENTRY,false); System.out.println(res19); // >>> OK String res20 = jedis.xgroupCreate("race:italy","italy_riders",StreamEntryID.LAST_ENTRY,true); System.out.println(res20); // >>> OK StreamEntryID id1 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Castilaa");}},XAddParams.xAddParams()); StreamEntryID id2 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Royce");}},XAddParams.xAddParams()); StreamEntryID id3 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Sam-Bodden");}},XAddParams.xAddParams()); StreamEntryID id4 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Prickett");}},XAddParams.xAddParams()); StreamEntryID id5 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Norem");}},XAddParams.xAddParams()); List<Map.Entry<String, List<StreamEntry>>> res21 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); System.out.println(res21); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] List<Map.Entry<String, List<StreamEntry>>> res22 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}}); System.out.println(res22); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] long res23 = jedis.xack("race:italy","italy_riders",id1); System.out.println(res23); // >>> 1 List<Map.Entry<String, List<StreamEntry>>> res24 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}}); System.out.println(res24); // >>> [race:italy=[]] List<Map.Entry<String, List<StreamEntry>>> res25 = jedis.xreadGroup("italy_riders","Bob", XReadGroupParams.xReadGroupParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); System.out.println(res25); // >>> [race:italy=[1701767632261-1 {rider=Royce}, 1701767632262-0 {rider=Sam-Bodden}]] StreamPendingSummary res26 = jedis.xpending("race:italy","italy_riders"); System.out.println(res26.getConsumerMessageCount()); // >>> {Bob=2} List<StreamPendingEntry> res27 = jedis.xpending("race:italy","italy_riders",XPendingParams.xPendingParams().start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(10)); System.out.println(res27); // >>> [1701768567412-1 Bob idle:0 times:1, 1701768567412-2 Bob idle:0 times:1] List<StreamEntry> res28 = jedis.xrange("race:italy",id2.toString(),id2.toString()); System.out.println(res28); // >>> [1701768744819-1 {rider=Royce}] List<StreamEntry> res29 = jedis.xclaim("race:italy","italy_riders","Alice", 0L, XClaimParams.xClaimParams().time(60000),id2); System.out.println(res29); // >>> [1701769004195-1 {rider=Royce}] Map.Entry<StreamEntryID, List<StreamEntry>> res30 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID("0-0"),XAutoClaimParams.xAutoClaimParams().count(1)); System.out.println(res30); // >>> [1701769266831-2=[1701769266831-1 {rider=Royce}] Map.Entry<StreamEntryID, List<StreamEntry>> res31 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID(id2.toString()),XAutoClaimParams.xAutoClaimParams().count(1)); System.out.println(res31); // >>> [0-0=[1701769605847-2 {rider=Sam-Bodden}] StreamInfo res32 = jedis.xinfoStream("race:italy"); System.out.println( res32.getStreamInfo() ); // >>> {radix-tree-keys=1, radix-tree-nodes=2, entries-added=5, length=5, groups=1, max-deleted-entry-id=0-0, first-entry=1701769637612-0 {rider=Castilaa}, last-generated-id=1701769637612-4, last-entry=1701769637612-4 {rider=Norem}, recorded-first-entry-id=1701769637612-0} List<StreamGroupInfo> res33 = jedis.xinfoGroups("race:italy"); for (StreamGroupInfo a : res33){ System.out.println( a.getGroupInfo() ); // >>> {last-delivered-id=1701770253659-0, lag=2, pending=2, name=italy_riders, consumers=2, entries-read=3} } List<StreamConsumersInfo> res34 = jedis.xinfoConsumers("race:italy","italy_riders"); for (StreamConsumerInfo a : res34){ System.out.println( a.getConsumerInfo() ); // {inactive=1, idle=1, pending=1, name=Alice} , {inactive=3, idle=3, pending=1, name=Bob} } jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Jones");}},XAddParams.xAddParams().maxLen(10)); jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Wood");}},XAddParams.xAddParams().maxLen(10)); jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Henshaw");}},XAddParams.xAddParams().maxLen(10)); long res35 = jedis.xlen("race:italy"); System.out.println(res35); // >>> 8 List<StreamEntry> res36 = jedis.xrange("race:italy","-","+"); System.out.println(res36); // >>> [1701771219852-0 {rider=Castilaa}, 1701771219852-1 {rider=Royce}, 1701771219853-0 {rider=Sam-Bodden}, 1701771219853-1 {rider=Prickett}, 1701771219853-2 {rider=Norem}, 1701771219858-0 {rider=Jones}, 1701771219858-1 {rider=Wood}, 1701771219859-0 {rider=Henshaw}] StreamEntryID id6 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Smith");}},XAddParams.xAddParams().maxLen(2)); List<StreamEntry> res37 = jedis.xrange("race:italy","-","+"); System.out.println(res37); // >>> [1701771067332-1 {rider=Henshaw}, 1701771067332-2 {rider=Smith}] long res38 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10).exactTrimming()); System.out.println(res38); /// >>> 0 long res39 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10)); System.out.println(res39); /// >>> 0 List<StreamEntry> res40 = jedis.xrange("race:italy","-","+"); System.out.println(res40); // >>> [1701771356428-2 {rider=Henshaw}, 1701771356429-0 {rider=Smith}] long res41 = jedis.xdel("race:italy",id6); System.out.println(res41); // >>> 1 List<StreamEntry> res42 = jedis.xrange("race:italy","-","+"); System.out.println(res42); // >>> [1701771517639-1 {rider=Henshaw}] jedis.close(); } }package example_commands_test import ( "context" "fmt" "github.com/redis/go-redis/v9" ) func ExampleClient_xadd() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res1, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.Println(res1) // >>> 1692632086370-0 res2, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.PrintLn(res2) // >>> 1692632094485-0 res3, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.Println(res3) // >>> 1692632102976-0 xlen, err := rdb.XLen(ctx, "race:france").Result() if err != nil { panic(err) } fmt.Println(xlen) // >>> 3 } func ExampleClient_racefrance1() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, ID: "1692632094485-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, ID: "1692632102976-0", }).Result() if err != nil { panic(err) } res4, err := rdb.XRangeN(ctx, "race:france", "1691765278160-0", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res4) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla... res5, err := rdb.XRead(ctx, &redis.XReadArgs{ Streams: []string{"race:france", "0"}, Count: 100, Block: 300, }).Result() if err != nil { panic(err) } fmt.Println(res5) // >>> // [{race:france [{1692632086370-0 map[location_id:1 position:1... res6, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2, }, }).Result() if err != nil { panic(err) } //fmt.Println(res6) // >>> 1692632147973-0 res7, err := rdb.XLen(ctx, "race:france").Result() if err != nil { panic(err) } fmt.Println(res7) // >>> 4 } func ExampleClient_raceusa() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res8, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Castilla", }, ID: "0-1", }).Result() if err != nil { panic(err) } fmt.Println(res8) // >>> 0-1 res9, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Norem", }, ID: "0-2", }).Result() if err != nil { panic(err) } fmt.Println(res9) // >>> 0-2 res10, err := rdb.XAdd(ctx, &redis.XAddArgs{ Values: map[string]interface{}{ "racer": "Prickett", }, ID: "0-1", }).Result() if err != nil { // fmt.Println(err) // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } res11, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Prickett", }, ID: "0-*", }).Result() if err != nil { panic(err) } fmt.Println(res11) // >>> 0-3 } func ExampleClient_racefrance2() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, ID: "1692632094485-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, ID: "1692632102976-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2, }, ID: "1692632147973-0", }).Result() if err != nil { panic(err) } res12, err := rdb.XRange(ctx, "race:france", "-", "+").Result() if err != nil { panic(err) } fmt.Println(res12) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla... res13, err := rdb.XRange(ctx, "race:france", "1692632086369", "1692632086371", ).Result() if err != nil { panic(err) } fmt.Println(res13) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0}] res14, err := rdb.XRangeN(ctx, "race:france", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res14) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}] res15, err := rdb.XRangeN(ctx, "race:france", "(1692632094485-0", "+", 2, ).Result() if err != nil { panic(err) } fmt.Println(res15) // >>> [{1692632102976-0 map[location_id:1 position:2 rider:Prickett speed:29.7] 0 0} {1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}] res16, err := rdb.XRangeN(ctx, "race:france", "(1692632147973-0", "+", 2, ).Result() if err != nil { panic(err) } fmt.Println(res16) // >>> [] res17, err := rdb.XRevRangeN(ctx, "race:france", "+", "-", 1).Result() if err != nil { panic(err) } fmt.Println(res17) // >>> [{1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}] res18, err := rdb.XRead(ctx, &redis.XReadArgs{ Streams: []string{"race:france", "0"}, Count: 2, }).Result() if err != nil { panic(err) } fmt.Println(res18) // >>> [{race:france [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}]}] } func ExampleClient_xgroupcreate() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } res19, err := rdb.XGroupCreate(ctx, "race:france", "france_riders", "$").Result() if err != nil { panic(err) } fmt.Println(res19) // >>> OK } func ExampleClient_xgroupcreatemkstream() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res20, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } fmt.Println(res20) // >>> OK } func ExampleClient_xgroupread() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Castilla"}, }).Result() // >>> 1692632639151-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Royce"}, }).Result() // >>> 1692632647899-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Sam-Bodden"}, }).Result() // >>> 1692632662819-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Prickett"}, }).Result() // >>> 1692632670501-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Norem"}, }).Result() // >>> 1692632678249-0 if err != nil { panic(err) } // fmt.Println(res25) res21, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Alice", Count: 1, }).Result() if err != nil { panic(err) } // fmt.Println(res21) // >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}] xlen, err := rdb.XLen(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(xlen) } func ExampleClient_raceitaly() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Castilla"}, ID: "1692632639151-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Royce"}, ID: "1692632647899-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Sam-Bodden"}, ID: "1692632662819-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Prickett"}, ID: "1692632670501-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Norem"}, ID: "1692632678249-0", }).Result() if err != nil { panic(err) } _, err = rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Alice", Count: 1, }).Result() if err != nil { panic(err) } res22, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", "0"}, Group: "italy_riders", Consumer: "Alice", }).Result() if err != nil { panic(err) } fmt.Println(res22) // >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}] res23, err := rdb.XAck(ctx, "race:italy", "italy_riders", "1692632639151-0", ).Result() if err != nil { panic(err) } fmt.Println(res23) // >>> 1 res24, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", "0"}, Group: "italy_riders", Consumer: "Alice", }).Result() if err != nil { panic(err) } fmt.Println(res24) // >>> [{race:italy []}] res25, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Bob", Count: 2, }).Result() if err != nil { panic(err) } fmt.Println(res25) // >>> [{race:italy [{1692632647899-0 map[rider:Royce] 0 0} {1692632662819-0 map[rider:Sam-Bodden] 0 0}]}] res26, err := rdb.XPending(ctx, "race:italy", "italy_riders").Result() if err != nil { panic(err) } fmt.Println(res26) // >>> &{2 1692632647899-0 1692632662819-0 map[Bob:2]} res27, err := rdb.XPendingExt(ctx, &redis.XPendingExtArgs{ Stream: "race:italy", Group: "italy_riders", Start: "-", End: "+", Count: 10, }).Result() if err != nil { panic(err) } // fmt.Println(res27) // >>> [{1692632647899-0 Bob 0s 1} {1692632662819-0 Bob 0s 1}] res28, err := rdb.XRange(ctx, "race:italy", "1692632647899-0", "1692632647899-0", ).Result() if err != nil { panic(err) } fmt.Println(res28) // >>> [{1692632647899-0 map[rider:Royce] 0 0}] res29, err := rdb.XClaim(ctx, &redis.XClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Alice", MinIdle: 0, Messages: []string{"1692632647899-0"}, }).Result() if err != nil { panic(err) } fmt.Println(res29) res30, res30a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Alice", Start: "0-0", Count: 1, }).Result() if err != nil { panic(err) } fmt.Println(res30) // >>> [{1692632647899-0 map[rider:Royce] 0 0}] fmt.Println(res30a) // >>> 1692632662819-0 res31, res31a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Lora", Start: "(1692632662819-0", Count: 1, }).Result() if err != nil { panic(err) } fmt.Println(res31) // >>> [] fmt.Println(res31a) // >>> 0-0 res32, err := rdb.XInfoStream(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res32.Length) // >>> 5 fmt.Println(res32.FirstEntry) // >>> {1692632639151-0 map[rider:Castilla] 0 0} res33, err := rdb.XInfoGroups(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res33) // >>> [{italy_riders 3 2 1692632662819-0 3 2}] res34, err := rdb.XInfoConsumers(ctx, "race:italy", "italy_riders").Result() if err != nil { panic(err) } // fmt.Println(res34) // >>> [{Alice 1 1ms 1ms} {Bob 1 2ms 2ms} {Lora 0 1ms -1ms}] _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Jones"}, }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Wood"}, }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Henshaw"}, }, ).Result() if err != nil { panic(err) } res35, err := rdb.XLen(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res35) // >>> 2 res36, err := rdb.XRange(ctx, "race:italy", "-", "+").Result() if err != nil { panic(err) } // fmt.Println(res36) // >>> [{1726649529170-1 map[rider:Wood] 0 0} {1726649529171-0 map[rider:Henshaw] 0 0}] res37, err := rdb.XTrimMaxLen(ctx, "race:italy", 10).Result() if err != nil { panic(err) } fmt.Println(res37) // >>> 0 res38, err := rdb.XTrimMaxLenApprox(ctx, "race:italy", 10, 20).Result() if err != nil { panic(err) } fmt.Println(res38) // >>> 0 } func ExampleClient_xdel() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Wood"}, ID: "1692633198206-0", }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Henshaw"}, ID: "1692633208557-0", }, ).Result() if err != nil { panic(err) } res39, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res39) // >>> [{1692633198206-0 map[rider:Wood] 0 0} {1692633208557-0 map[rider:Henshaw] 0 0}] res40, err := rdb.XDel(ctx, "race:italy", "1692633208557-0").Result() if err != nil { panic(err) } fmt.Println(res40) // 1 res41, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res41) // >>> [{1692633198206-0 map[rider:Wood] 0 0}] }using NRedisStack.Tests; using StackExchange.Redis; public class StreamTutorial { public void Run() { var muxer = ConnectionMultiplexer.Connect("localhost:6379"); var db = muxer.GetDatabase(); RedisValue res1 = db.StreamAdd( "race:france", [ new("rider", "Castilla"), new("speed", 30.2), new("position", 1), new("location_id", 1) ] ); Console.WriteLine(res1); // >>> 1712668482289-0 RedisValue res2 = db.StreamAdd( "race:france", [ new("rider", "Norem"), new("speed", 28.8), new("position", 3), new("location_id", 1) ] ); Console.WriteLine(res2); // >>> 1712668766534-1 RedisValue res3 = db.StreamAdd( "race:france", [ new("rider", "Prickett"), new("speed", 29.7), new("position", 2), new("location_id", 1) ] ); Console.WriteLine(res3); // >>> 1712669055705-0 // Tests for 'xadd' step. StreamEntry[] res4 = db.StreamRange("race:france", "1712668482289-0", "+", 2); foreach (StreamEntry entry in res4) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xrange' step. StreamEntry[] res5 = db.StreamRead("race:france", 0, 100); foreach (StreamEntry entry in res4) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // Tests for 'xread_block' step. RedisValue res6 = db.StreamAdd( "race:france", [ new("rider", "Castilla"), new("speed", 29.9), new("position", 1), new("location_id", 2) ] ); Console.WriteLine(res6); // >>> 1712675674750-0 // Tests for 'xadd_2' step. long res7 = db.StreamLength("race:france"); Console.WriteLine(res7); // >>> 4 // Tests for 'xlen' step. RedisValue res8 = db.StreamAdd( "race:usa", [ new("racer", "Castilla") ], "0-1" ); Console.WriteLine(res8); // >>> 0-1 RedisValue res9 = db.StreamAdd( "race:usa", [ new("racer", "Norem") ], "0-2" ); Console.WriteLine(res9); // >>> 0-2 // Tests for 'xadd_id' step. try { RedisValue res10 = db.StreamAdd( "race:usa", [ new("racer", "Prickett") ], "0-1" ); } catch (RedisServerException ex) { Console.WriteLine(ex); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } // Tests for 'xadd_bad_id' step. RedisValue res11 = ""; Version version = muxer.GetServer("localhost:6379").Version; if (version.Major >= 7) { res11 = db.StreamAdd( "race:usa", [ new("rider", "Norem") ], "0-*" ); Console.WriteLine(res11); // >>> "0-3" } // Tests for 'xadd_7' step. StreamEntry[] res12 = db.StreamRange("race:france", "-", "+"); foreach (StreamEntry entry in res12) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrange_all' step. StreamEntry[] res13 = db.StreamRange("race:france", 1712668482289, 1712668482291); foreach (StreamEntry entry in res13) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // Tests for 'xrange_time' step. StreamEntry[] res14 = db.StreamRange("race:france", "-", "+", 2); foreach (StreamEntry entry in res14) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xrange_step_1' step. StreamEntry[] res15 = db.StreamRange("race:france", "(1712668766534-1", "+", 2); foreach (StreamEntry entry in res15) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrange_step_2' step. StreamEntry[] res16 = db.StreamRange("race:france", "(1712675674750-0", "+", 2); foreach (StreamEntry entry in res16) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> <empty array> // Tests for 'xrange_empty' step. StreamEntry[] res17 = db.StreamRange("race:france", "+", "-", 1, Order.Descending); foreach (StreamEntry entry in res17) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrevrange' step. StreamEntry[] res18 = db.StreamRead("race:france", 0, 2); foreach (StreamEntry entry in res18) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xread' step. bool res19 = db.StreamCreateConsumerGroup("race:france", "france_riders", "$"); Console.WriteLine(res19); // >>> true // Tests for 'xgroup_create' step. bool res20 = db.StreamCreateConsumerGroup("race:italy", "italy_riders", "$", true); Console.WriteLine(res20); // >>> true // Tests for 'xgroup_create_mkstream' step. RedisValue groupRes = db.StreamAdd( "race:italy", [new("rider", "Castilla")] ); // 1712744323758-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Royce")] ); // 1712744358384-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Sam-Bodden")] ); // 1712744379676-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Prickett")] ); // 1712744399401-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Norem")] ); // 1712744413117-0 StreamEntry[] res21 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", ">", 1); foreach (StreamEntry entry in res21) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744323758-0: [rider: Castilla] // Tests for 'xgroup_read' step. StreamEntry[] res22 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0"); foreach (StreamEntry entry in res22) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); // >>> 1712744323758-0: [rider: Castilla] } // Tests for 'xgroup_read_id' step. long res23 = db.StreamAcknowledge("race:italy", "italy_riders", "1712744323758-0"); Console.WriteLine(res23); // >>> 1 StreamEntry[] res24 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0"); foreach (StreamEntry entry in res24) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> <empty array> // Tests for 'xack' step. StreamEntry[] res25 = db.StreamReadGroup("race:italy", "italy_riders", "Bob", ">", 2); foreach (StreamEntry entry in res25) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // >>> 1712744379676-0: [rider: Sam-Bodden] // Tests for 'xgroup_read_bob' step. StreamPendingInfo res26 = db.StreamPending("race:italy", "italy_riders"); Console.WriteLine($"pending: {res26.PendingMessageCount}, min: {res26.LowestPendingMessageId}, max: {res26.HighestPendingMessageId}, consumers:[{string.Join(", ", res26.Consumers.Select(c => $"{c.Name}: {c.PendingMessageCount}"))}]"); // >>> pending: 2, min: 1712747506906-0, max: 1712747506907-0, consumers:[name: Bob, pending:2] // Tests for 'xpending' step. StreamPendingMessageInfo[] res27 = db.StreamPendingMessages( "race:italy", "italy_riders", 10, "", "-", "+" ); foreach (StreamPendingMessageInfo info in res27) { Console.WriteLine($"message_id: {info.MessageId}, consumer: {info.ConsumerName}, time_since_delivered: {info.IdleTimeInMilliseconds}, times_delivered: {info.DeliveryCount}"); } // >>> message_id: min: 1712747506906-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1 // >>> message_id: min: 1712747506907-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1 // Tests for 'xpending_plus_minus' step. StreamEntry[] res28 = db.StreamRange("race:italy", "1712744358384-0", "1712744358384-0"); foreach (StreamEntry entry in res28) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // Tests for 'xrange_pending' step. StreamEntry[] res29 = db.StreamClaim( "race:italy", "italy_riders", "Alice", 60000, [1712744358384 - 0] ); foreach (StreamEntry entry in res29) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // Tests for 'xclaim' step. StreamAutoClaimResult res30 = db.StreamAutoClaim( "race:italy", "italy_riders", "Alice", 1, "0-0", 1 ); Console.WriteLine($"{res30.NextStartId}, ({string.Join(", ", res30.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})"); // >>> 1712744379676-0, (1712744358384-0: [rider: Royce]) // Tests for 'xautoclaim' step. StreamAutoClaimResult res31 = db.StreamAutoClaim( "race:italy", "italy_riders", "Alice", 1, "(1712744358384-0", 1 ); Console.WriteLine($"{res31.NextStartId}, ({string.Join(", ", res31.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})"); // >>> 0-0, (1712744379676-0: [rider: Sam-Bodden]) // Tests for 'xautoclaim_cursor' step. StreamInfo res32 = db.StreamInfo("race:italy"); Console.WriteLine($"length: {res32.Length}, radix-tree-keys: {res32.RadixTreeKeys}, radix-tree-nodes: {res32.RadixTreeNodes}, last-generated-id: {res32.LastGeneratedId}, first-entry: {$"{res32.FirstEntry.Id}: [{string.Join(", ", res32.FirstEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}, last-entry: {$"{res32.LastEntry.Id}: [{string.Join(", ", res32.LastEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}"); // >>> length: 5, radix-tree-keys: 1, radix-tree-nodes: 2, last-generated-id: 1712756762686-1, first-entry: 1712756762685-0: [rider: Castilla], last-entry: 1712756762686-1: [rider: Norem] // Tests for 'xinfo' step. StreamGroupInfo[] res33 = db.StreamGroupInfo("race:italy"); foreach (StreamGroupInfo info in res33) { Console.WriteLine($"name: {info.Name}, consumers: {info.ConsumerCount}, pending: {info.PendingMessageCount}, last-delivered-id: {info.LastDeliveredId}"); } // >>> name: italy_riders, consumers: 2, pending: 2, last-delivered-id: 1712757192730-2 // Tests for 'xinfo_groups' step. StreamConsumerInfo[] res34 = db.StreamConsumerInfo("race:italy", "italy_riders"); foreach (StreamConsumerInfo info in res34) { Console.WriteLine($"name: {info.Name}, pending: {info.PendingMessageCount}, idle: {info.IdleTimeInMilliseconds}"); } // >>> name: Alice, pending: 1, idle: 7717 // >>> name: Bob, pending: 0, idle: 7722 // Tests for 'xinfo_consumers' step. db.StreamAdd( "race:italy", [new("rider", "Jones")], null, 2, true ); db.StreamAdd( "race:italy", [new("rider", "Wood")], null, 2, true ); db.StreamAdd( "race:italy", [new("rider", "Henshaw")], null, 2, true ); long res35 = db.StreamLength("race:italy"); Console.WriteLine(res35); // >>> 8 StreamEntry[] res36 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res36) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712758336128-0: [rider: Castilla] // >>> 1712758336128-1: [rider: Royce] // >>> 1712758336128-2: [rider: Sam-Bodden] // >>> 1712758336129-0: [rider: Prickett] // >>> 1712758336139-0: [rider: Norem] // >>> 1712758340854-0: [rider: Jones] // >>> 1712758341645-0: [rider: Wood] // >>> 1712758342134-0: [rider: Henshaw] db.StreamAdd( "race:italy", [new("rider", "Smith")], null, 2, false ); StreamEntry[] res37 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res37) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // 1712758746476-1: [rider: Henshaw] // 1712758746477-0: [rider: Smith] // Tests for 'maxlen' step. long res38 = db.StreamTrim("race:italy", 10, false); Console.WriteLine(res38); // >>> 0 // Tests for 'xtrim' step. long res39 = db.StreamTrim("race:italy", 10, true); Console.WriteLine(res39); // >>> 0 // Tests for 'xtrim2' step. StreamEntry[] res40 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res40) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712759694003-0: [rider: Henshaw] // >>> 1712759694003-1: [rider: Smith] long res41 = db.StreamDelete("race:italy", ["1712759694003-1"]); Console.WriteLine(res41); // >>> 1 StreamEntry[] res42 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res42) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712759694003-0: [rider: Henshaw] // Tests for 'xdel' step. } }require 'redis' r = Redis.new res1 = r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => 30.2, 'position' => 1, 'location_id' => 1 }) puts res1 # 1692632086370-0, for example res2 = r.xadd('race:france', { 'rider' => 'Norem', 'speed' => 28.8, 'position' => 3, 'location_id' => 1 }) puts res2 # 1692632094485-0, for example res3 = r.xadd('race:france', { 'rider' => 'Prickett', 'speed' => 29.7, 'position' => 2, 'location_id' => 1 }) puts res3 # 1692632102976-0, for example r.del('race:france') r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1' }, id: '1692632086370-0') r.xadd('race:france', { 'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1' }, id: '1692632094485-0') r.xadd('race:france', { 'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1' }, id: '1692632102976-0') r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2' }, id: '1692632147973-0') res4 = r.xrange('race:france', '1692632086370-0', '+', count: 2) puts res4.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') res5 = r.xread(['race:france'], ['$'], count: 100, block: 300) puts res5.inspect # {} res6 = r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => 29.9, 'position' => 1, 'location_id' => 2 }) puts res6 # 1692632147973-0, for example r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632147973-0') res7 = r.xlen('race:france') puts res7 # 4 r.del('race:usa') res8 = r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1') puts res8 # 0-1 res9 = r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2') puts res9 # 0-2 begin r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-1') rescue Redis::CommandError => e puts e.message # ERR The ID specified in XADD is equal or smaller than the target stream top item end r.del('race:usa') r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1') r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2') res10 = r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-*') puts res10 # 0-3 r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res11 = r.xrange('race:france', '-', '+') puts res11.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}], # ["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}], # ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') res12 = r.xrange('race:france', '1692632086369', '1692632086371') puts res12.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res13 = r.xrange('race:france', '-', '+', count: 2) puts res13.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res14 = r.xrange('race:france', '(1692632094485-0', '+', count: 2) puts res14.inspect # [["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}], # ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] res15 = r.xrange('race:france', '(1692632147973-0', '+', count: 2) puts res15.inspect # [] res16 = r.xrevrange('race:france', '+', '-', count: 1) puts res16.inspect # [["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] res17 = r.xread(['race:france'], ['0'], count: 2) puts res17.inspect # {"race:france"=>[["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]]} r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') res18 = r.xgroup(:create, 'race:france', 'france_riders', '$') puts res18 # OK r.del('race:italy') res19 = r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true) puts res19 # OK r.del('race:italy') r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true) r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0') r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0') r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0') r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0') r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0') res20 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['>'], count: 1) puts res20.inspect # {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]} res21 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0'], count: 1) puts res21.inspect # {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]} res22 = r.xack('race:italy', 'italy_riders', '1692632639151-0') puts res22 # 1 res23 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0']) puts res23.inspect # {"race:italy"=>[]} res24 = r.xreadgroup('italy_riders', 'Bob', ['race:italy'], ['>'], count: 2) puts res24.inspect # {"race:italy"=>[["1692632647899-0", {"rider"=>"Royce"}], # ["1692632662819-0", {"rider"=>"Sam-Bodden"}]]} res25 = r.xpending('race:italy', 'italy_riders') puts res25.inspect # {"size"=>2, "min_entry_id"=>"1692632647899-0", "max_entry_id"=>"1692632662819-0", "consumers"=>{"Bob"=>"2"}} res26 = r.xpending('race:italy', 'italy_riders', '-', '+', 10) puts res26.inspect res27 = r.xrange('race:italy', '1692632647899-0', '1692632647899-0') puts res27.inspect # [["1692632647899-0", {"rider"=>"Royce"}]] res28 = r.xclaim('race:italy', 'italy_riders', 'Alice', 0, '1692632647899-0') puts res28.inspect # [["1692632647899-0", {"rider"=>"Royce"}]] res29 = r.xautoclaim('race:italy', 'italy_riders', 'Alice', 0, '0-0', count: 1) puts res29.inspect # {"next"=>"1692632662819-0", "entries"=>[["1692632647899-0", {"rider"=>"Royce"}]]} res30 = r.xautoclaim('race:italy', 'italy_riders', 'Lora', 0, res29['next'], count: 1) puts res30.inspect # {"next"=>"0-0", "entries"=>[["1692632662819-0", {"rider"=>"Sam-Bodden"}]]} res31 = r.xinfo(:stream, 'race:italy') puts res31.inspect res32 = r.xinfo(:groups, 'race:italy') puts res32.inspect res33 = r.xinfo(:consumers, 'race:italy', 'italy_riders') puts res33.inspect r.del('race:italy') r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0') r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0') r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0') r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0') r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0') r.xadd('race:italy', {'rider' => 'Jones'}, id: '1692633189161-0', maxlen: 2) r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0', maxlen: 2) r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0', maxlen: 2) res34 = r.xlen('race:italy') puts res34 # 2 res35 = r.xrange('race:italy', '-', '+') puts res35.inspect # [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]] res36 = r.xtrim('race:italy', 10, approximate: false) puts res36 # 0 r.del('mystream') 1.upto(10) do |n| r.xadd('mystream', {'field' => 'value'}, id: "#{n}-0") end res37 = r.xtrim('mystream', 10, approximate: true) puts res37 # 0 r.del('race:italy') r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0') r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0') res38 = r.xrange('race:italy', '-', '+', count: 2) puts res38.inspect # [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]] res39 = r.xdel('race:italy', '1692633208557-0') puts res39 # 1 res40 = r.xrange('race:italy', '-', '+', count: 2) puts res40.inspect # [["1692633198206-0", {"rider"=>"Wood"}]]mod stream_tests { use redis::{ streams::{ StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply, StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply, StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode, StreamTrimOptions, }, Commands, }; use std::{thread::sleep, time::Duration}; fn delete_keys(r: &mut redis::Connection, keys: &[&str]) { let _: usize = r.del(keys).unwrap_or(0); } fn add_france_fixed(r: &mut redis::Connection) { delete_keys(r, &["race:france"]); let _: Option<String> = r .xadd( "race:france", "1692632086370-0", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .expect("add france 1"); let _: Option<String> = r .xadd( "race:france", "1692632094485-0", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .expect("add france 2"); let _: Option<String> = r .xadd( "race:france", "1692632102976-0", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .expect("add france 3"); let _: Option<String> = r .xadd( "race:france", "1692632147973-0", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .expect("add france 4"); } fn seed_usa_fixed(r: &mut redis::Connection) { delete_keys(r, &["race:usa"]); let _: Option<String> = r .xadd("race:usa", "0-1", &[("racer", "Castilla")]) .expect("add usa 1"); let _: Option<String> = r .xadd("race:usa", "0-2", &[("racer", "Norem")]) .expect("add usa 2"); } fn seed_italy_group_base(r: &mut redis::Connection) { delete_keys(r, &["race:italy"]); let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .expect("create italy group"); let _: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .expect("add italy 1"); let _: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .expect("add italy 2"); let _: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .expect("add italy 3"); let _: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .expect("add italy 4"); let _: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .expect("add italy 5"); } fn seed_italy_alice_pending(r: &mut redis::Connection) { seed_italy_group_base(r); let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .expect("alice read pending"); } fn seed_italy_after_ack(r: &mut redis::Connection) { seed_italy_alice_pending(r); let _: usize = r .xack("race:italy", "italy_riders", &["1692632639151-0"]) .expect("ack first italy message"); } fn seed_italy_bob_pending(r: &mut redis::Connection) { seed_italy_after_ack(r); let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .expect("bob read pending"); } fn seed_italy_info_state(r: &mut redis::Connection) { seed_italy_bob_pending(r); sleep(Duration::from_millis(5)); let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .expect("alice claim"); sleep(Duration::from_millis(5)); let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"]) .expect("lora claim"); } fn seed_trim_stream(r: &mut redis::Connection) { delete_keys(r, &["mystream"]); for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] { let _: Option<String> = r .xadd("mystream", id, &[("field", "value")]) .expect("seed mystream"); } } fn run() { let mut r = match redis::Client::open("redis://127.0.0.1") { Ok(client) => match client.get_connection() { Ok(conn) => conn, Err(e) => { println!("Failed to connect to Redis: {e}"); return; } }, Err(e) => { println!("Failed to create Redis client: {e}"); return; } }; let res1 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .expect("xadd 1"); res.expect("missing stream id") }; println!("{res1}"); // >>> 1692632086370-0 let res2 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .expect("xadd 2"); res.expect("missing stream id") }; println!("{res2}"); // >>> 1692632094485-0 let res3 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .expect("xadd 3"); res.expect("missing stream id") }; println!("{res3}"); // >>> 1692632102976-0 add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r); let opts = StreamReadOptions::default().count(100).block(300); if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts) { let res: Option<StreamReadReply> = res; println!("{res:?}"); // >>> None } if let Ok(res) = r.xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 1692632147973-0 } add_france_fixed(&mut r); if let Ok(res) = r.xlen("race:france") { let res: usize = res; println!("{res}"); // >>> 4 } delete_keys(&mut r, &["race:usa"]); if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-1 } if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-2 } let res: redis::RedisResult<Option<String>> = r.xadd("race:usa", "0-1", &[("racer", "Prickett")]); match res { Ok(_) => {} Err(e) => { let msg = e.to_string(); println!("{msg}"); // >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item } } seed_usa_fixed(&mut r); if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-3 } add_france_fixed(&mut r); if let Ok(res) = r.xrange_all("race:france") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [] } add_france_fixed(&mut r); if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); let opts = StreamReadOptions::default().count(2); if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let reply = res.expect("xread should return data"); let view: Vec<_> = reply .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])] } add_france_fixed(&mut r); if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$") { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]); if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$") { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]); let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .expect("create italy group"); let italy_1: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .expect("italy1"); let italy_1 = italy_1.expect("missing stream id"); println!("{italy_1}"); // >>> 1692632639151-0 let italy_2: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .expect("italy2"); let italy_2 = italy_2.expect("missing stream id"); println!("{italy_2}"); // >>> 1692632647899-0 let italy_3: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .expect("italy3"); let italy_3 = italy_3.expect("missing stream id"); println!("{italy_3}"); // >>> 1692632662819-0 let italy_4: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .expect("italy4"); let italy_4 = italy_4.expect("missing stream id"); println!("{italy_4}"); // >>> 1692632670501-0 let italy_5: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .expect("italy5"); let italy_5 = italy_5.expect("missing stream id"); println!("{italy_5}"); // >>> 1692632678249-0 let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup read should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r); let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r); if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]) { let res: usize = res; println!("{res}"); // >>> 1 } let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [])] } seed_italy_after_ack(&mut r); let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("bob should receive data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])] } seed_italy_bob_pending(&mut r); if let Ok(res) = r.xpending("race:italy", "italy_riders") { let res: StreamPendingReply = res; let view = match res { StreamPendingReply::Empty => None, StreamPendingReply::Data(data) => Some(( data.count, data.start_id.clone(), data.end_id.clone(), data.consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending)) .collect::<Vec<_>>(), )), } .expect("pending summary"); println!("{view:?}"); // >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)]) } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10) { let res: StreamPendingCountReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), entry.consumer.clone(), entry.last_delivered_ms, entry.times_delivered, ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)] } seed_italy_bob_pending(&mut r); if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); if let Ok(res) = r.xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) { let res: redis::streams::StreamClaimReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); let opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r.xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts) { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])]) } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); let first_opts = StreamAutoClaimOptions::default().count(1); let _: redis::streams::StreamAutoClaimReply = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts) .expect("first autoclaim"); let next_opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r.xautoclaim_options( "race:italy", "italy_riders", "Lora", 1, "(1692632647899-0", next_opts, ) { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])]) } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_stream("race:italy") { let res: StreamInfoStreamReply = res; let view = ( res.length, res.radix_tree_keys, res.groups, res.last_generated_id.clone(), res.first_entry.id.clone(), res.last_entry.id.clone(), ); println!("{view:?}"); // >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0") } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_groups("race:italy") { let res: StreamInfoGroupsReply = res; let view: Vec<_> = res .groups .iter() .map(|group| { ( group.name.clone(), group.consumers, group.pending, group.last_delivered_id.clone(), ) }) .collect(); println!("{view:?}"); // >>> [("italy_riders", 3, 2, "1692632662819-0")] } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders") { let res: StreamInfoConsumersReply = res; let mut view: Vec<_> = res .consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle)) .collect(); view.sort_by(|a, b| a.0.cmp(&b.0)); println!("{view:?}"); // >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)] } delete_keys(&mut r, &["race:italy"]); let max1: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")]) .expect("maxlen add 1"); let max1 = max1.expect("missing stream id"); println!("{max1}"); // >>> 1-0 let max2: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")]) .expect("maxlen add 2"); let max2 = max2.expect("missing stream id"); println!("{max2}"); // >>> 2-0 let max3: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")]) .expect("maxlen add 3"); let max3 = max3.expect("missing stream id"); println!("{max3}"); // >>> 3-0 if let Ok(res) = r.xlen("race:italy") { let res: usize = res; println!("{res}"); // >>> 2 } if let Ok(res) = r.xrange_all("race:italy") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } delete_keys(&mut r, &["race:italy"]); let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).expect("trim seed 1"); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).expect("trim seed 2"); if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)) { let res: usize = res; println!("{res}"); // >>> 0 } seed_trim_stream(&mut r); if let Ok(res) = r.xtrim_options( "mystream", &StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10), ) { let res: usize = res; println!("{res}"); // >>> 0 } delete_keys(&mut r, &["race:italy"]); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).expect("xdel seed 1"); let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).expect("xdel seed 2"); if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } if let Ok(res) = r.xdel("race:italy", &["3-0"]) { let res: usize = res; println!("{res}"); // >>> 1 } if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])] } } }mod tests { use redis::{ streams::{ StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply, StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply, StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode, StreamTrimOptions, }, AsyncCommands, }; use tokio::time::{sleep, Duration}; async fn delete_keys(r: &mut redis::aio::MultiplexedConnection, keys: &[&str]) { let _: usize = r.del(keys).await.unwrap_or(0); } async fn add_france_fixed(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:france"]).await; let _: Option<String> = r .xadd( "race:france", "1692632086370-0", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .await .expect("add france 1"); let _: Option<String> = r .xadd( "race:france", "1692632094485-0", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .await .expect("add france 2"); let _: Option<String> = r .xadd( "race:france", "1692632102976-0", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .await .expect("add france 3"); let _: Option<String> = r .xadd( "race:france", "1692632147973-0", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .await .expect("add france 4"); } async fn seed_usa_fixed(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:usa"]).await; let _: Option<String> = r .xadd("race:usa", "0-1", &[("racer", "Castilla")]) .await .expect("add usa 1"); let _: Option<String> = r .xadd("race:usa", "0-2", &[("racer", "Norem")]) .await .expect("add usa 2"); } async fn seed_italy_group_base(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:italy"]).await; let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .await .expect("create italy group"); let _: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .await .expect("add italy 1"); let _: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .await .expect("add italy 2"); let _: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .await .expect("add italy 3"); let _: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .await .expect("add italy 4"); let _: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .await .expect("add italy 5"); } async fn seed_italy_alice_pending(r: &mut redis::aio::MultiplexedConnection) { seed_italy_group_base(r).await; let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .await .expect("alice read pending"); } async fn seed_italy_after_ack(r: &mut redis::aio::MultiplexedConnection) { seed_italy_alice_pending(r).await; let _: usize = r .xack("race:italy", "italy_riders", &["1692632639151-0"]) .await .expect("ack first italy message"); } async fn seed_italy_bob_pending(r: &mut redis::aio::MultiplexedConnection) { seed_italy_after_ack(r).await; let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .await .expect("bob read pending"); } async fn seed_italy_info_state(r: &mut redis::aio::MultiplexedConnection) { seed_italy_bob_pending(r).await; sleep(Duration::from_millis(5)).await; let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .await .expect("alice claim"); sleep(Duration::from_millis(5)).await; let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"]) .await .expect("lora claim"); } async fn seed_trim_stream(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["mystream"]).await; for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] { let _: Option<String> = r .xadd("mystream", id, &[("field", "value")]) .await .expect("seed mystream"); } } async fn run() { let mut r = match redis::Client::open("redis://127.0.0.1") { Ok(client) => match client.get_multiplexed_async_connection().await { Ok(conn) => conn, Err(e) => { println!("Failed to connect to Redis: {e}"); return; } }, Err(e) => { println!("Failed to create Redis client: {e}"); return; } }; let res1: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .await .expect("xadd 1"); let res1 = res1.expect("missing stream id"); println!("{res1}"); // >>> 1692632086370-0 let res2: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .await .expect("xadd 2"); let res2 = res2.expect("missing stream id"); println!("{res2}"); // >>> 1692632094485-0 let res3: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .await .expect("xadd 3"); let res3 = res3.expect("missing stream id"); println!("{res3}"); // >>> 1692632102976-0 add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r).await; let opts = StreamReadOptions::default().count(100).block(300); if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts).await { let res: Option<StreamReadReply> = res; println!("{res:?}"); // >>> None } if let Ok(res) = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 1692632147973-0 } add_france_fixed(&mut r).await; if let Ok(res) = r.xlen("race:france").await { let res: usize = res; println!("{res}"); // >>> 4 } delete_keys(&mut r, &["race:usa"]).await; if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-1 } if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-2 } let res: redis::RedisResult<Option<String>> = r.xadd("race:usa", "0-1", &[("racer", "Prickett")]).await; match res { Ok(_) => {} Err(e) => { let msg = e.to_string(); println!("{msg}"); // >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item } } seed_usa_fixed(&mut r).await; if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-3 } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_all("race:france").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; let opts = StreamReadOptions::default().count(2); if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xread should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$").await { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]).await; if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$").await { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]).await; let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .await .expect("create italy group"); let italy_1: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .await .expect("italy1"); let italy_1 = italy_1.expect("missing stream id"); println!("{italy_1}"); // >>> 1692632639151-0 let italy_2: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .await .expect("italy2"); let italy_2 = italy_2.expect("missing stream id"); println!("{italy_2}"); // >>> 1692632647899-0 let italy_3: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .await .expect("italy3"); let italy_3 = italy_3.expect("missing stream id"); println!("{italy_3}"); // >>> 1692632662819-0 let italy_4: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .await .expect("italy4"); let italy_4 = italy_4.expect("missing stream id"); println!("{italy_4}"); // >>> 1692632670501-0 let italy_5: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .await .expect("italy5"); let italy_5 = italy_5.expect("missing stream id"); println!("{italy_5}"); // >>> 1692632678249-0 let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup read should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r).await; let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r).await; if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]).await { let res: usize = res; println!("{res}"); // >>> 1 } let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [])] } seed_italy_after_ack(&mut r).await; let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("bob should receive data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])] } seed_italy_bob_pending(&mut r).await; if let Ok(res) = r.xpending("race:italy", "italy_riders").await { let res: StreamPendingReply = res; let view = match res { StreamPendingReply::Empty => None, StreamPendingReply::Data(data) => Some(( data.count, data.start_id.clone(), data.end_id.clone(), data.consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending)) .collect::<Vec<_>>(), )), } .expect("pending summary"); println!("{view:?}"); // >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)]) } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10).await { let res: StreamPendingCountReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), entry.consumer.clone(), entry.last_delivered_ms, entry.times_delivered, ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)] } seed_italy_bob_pending(&mut r).await; if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; if let Ok(res) = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .await { let res: redis::streams::StreamClaimReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; let opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts) .await { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])]) } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; let first_opts = StreamAutoClaimOptions::default().count(1); let _: redis::streams::StreamAutoClaimReply = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts) .await .expect("first autoclaim"); let next_opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r .xautoclaim_options( "race:italy", "italy_riders", "Lora", 1, "(1692632647899-0", next_opts, ) .await { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])]) } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_stream("race:italy").await { let res: StreamInfoStreamReply = res; let view = ( res.length, res.radix_tree_keys, res.groups, res.last_generated_id.clone(), res.first_entry.id.clone(), res.last_entry.id.clone(), ); println!("{view:?}"); // >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0") } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_groups("race:italy").await { let res: StreamInfoGroupsReply = res; let view: Vec<_> = res .groups .iter() .map(|group| { ( group.name.clone(), group.consumers, group.pending, group.last_delivered_id.clone(), ) }) .collect(); println!("{view:?}"); // >>> [("italy_riders", 3, 2, "1692632662819-0")] } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders").await { let res: StreamInfoConsumersReply = res; let mut view: Vec<_> = res .consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle)) .collect(); view.sort_by(|a, b| a.0.cmp(&b.0)); println!("{view:?}"); // >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)] } delete_keys(&mut r, &["race:italy"]).await; let max1: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")]) .await .expect("maxlen add 1"); let max1 = max1.expect("missing stream id"); println!("{max1}"); // >>> 1-0 let max2: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")]) .await .expect("maxlen add 2"); let max2 = max2.expect("missing stream id"); println!("{max2}"); // >>> 2-0 let max3: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")]) .await .expect("maxlen add 3"); let max3 = max3.expect("missing stream id"); println!("{max3}"); // >>> 3-0 if let Ok(res) = r.xlen("race:italy").await { let res: usize = res; println!("{res}"); // >>> 2 } if let Ok(res) = r.xrange_all("race:italy").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } delete_keys(&mut r, &["race:italy"]).await; let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).await.expect("trim seed 1"); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).await.expect("trim seed 2"); if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)).await { let res: usize = res; println!("{res}"); // >>> 0 } seed_trim_stream(&mut r).await; if let Ok(res) = r .xtrim_options( "mystream", &StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10), ) .await { let res: usize = res; println!("{res}"); // >>> 0 } delete_keys(&mut r, &["race:italy"]).await; let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).await.expect("xdel seed 1"); let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).await.expect("xdel seed 2"); if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } if let Ok(res) = r.xdel("race:italy", &["3-0"]).await { let res: usize = res; println!("{res}"); // >>> 1 } if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])] } } } -
Read two stream entries starting at ID
1692632086370-0:Foundational: Retrieve stream entries within a range of IDs using XRANGE when you need to access historical data> XRANGE race:france 1692632086370-0 + COUNT 2 1) 1) "1692632086370-0" 2) 1) "rider" 2) "Castilla" 3) "speed" 4) "30.2" 5) "position" 6) "1" 7) "location_id" 8) "1" 2) 1) "1692632094485-0" 2) 1) "rider" 2) "Norem" 3) "speed" 4) "28.8" 5) "position" 6) "3" 7) "location_id" 8) "1"""" Code samples for Stream doc pages: https://redis.io/docs/latest/develop/data-types/streams/ """ import redis r = redis.Redis(decode_responses=True) res1 = r.xadd( "race:france", {"rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1}, ) print(res1) # >>> 1692629576966-0 res2 = r.xadd( "race:france", {"rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1}, ) print(res2) # >>> 1692629594113-0 res3 = r.xadd( "race:france", {"rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1}, ) print(res3) # >>> 1692629613374-0 res4 = r.xrange("race:france", "1691765278160-0", "+", 2) print( res4 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] res5 = r.xread(streams={"race:france": 0}, count=100, block=300) print( res5 ) # >>> [ # ['race:france', # [('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ), # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # )] # ] # ] res6 = r.xadd( "race:france", {"rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2}, ) print(res6) # >>> 1692629676124-0 res7 = r.xlen("race:france") print(res7) # >>> 4 res8 = r.xadd("race:usa", {"racer": "Castilla"}, id="0-1") print(res8) # >>> 0-1 res9 = r.xadd("race:usa", {"racer": "Norem"}, id="0-2") print(res9) # >>> 0-2 try: res10 = r.xadd("race:usa", {"racer": "Prickett"}, id="0-1") print(res10) # >>> 0-1 except redis.exceptions.ResponseError as e: print(e) # >>> WRONGID # Not yet implemented res11 = r.xrange("race:france", "-", "+") print( res11 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ), # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # ), # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res12 = r.xrange("race:france", 1692629576965, 1692629576967) print( res12 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ) # ] res13 = r.xrange("race:france", "-", "+", 2) print( res13 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] res14 = r.xrange("race:france", "(1692629594113-0", "+", 2) print( res14 ) # >>> [ # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # ), # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res15 = r.xrange("race:france", "(1692629676124-0", "+", 2) print(res15) # >>> [] res16 = r.xrevrange("race:france", "+", "-", 1) print( res16 ) # >>> [ # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res17 = r.xread(streams={"race:france": 0}, count=2) print( res17 ) # >>> [ # ['race:france', [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] # ] # ] res18 = r.xgroup_create("race:france", "france_riders", "$") print(res18) # >>> True res19 = r.xgroup_create("race:italy", "italy_riders", "$", mkstream=True) print(res19) # >>> True r.xadd("race:italy", {"rider": "Castilla"}) r.xadd("race:italy", {"rider": "Royce"}) r.xadd("race:italy", {"rider": "Sam-Bodden"}) r.xadd("race:italy", {"rider": "Prickett"}) r.xadd("race:italy", {"rider": "Norem"}) res20 = r.xreadgroup( streams={"race:italy": ">"}, consumername="Alice", groupname="italy_riders", count=1, ) print(res20) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]] res21 = r.xreadgroup( streams={"race:italy": 0}, consumername="Alice", groupname="italy_riders", count=1, ) print(res21) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]] res22 = r.xack("race:italy", "italy_riders", "1692629925771-0") print(res22) # >>> 1 res23 = r.xreadgroup( streams={"race:italy": 0}, consumername="Alice", groupname="italy_riders", count=1, ) print(res23) # >>> [['race:italy', []]] res24 = r.xreadgroup( streams={"race:italy": ">"}, consumername="Bob", groupname="italy_riders", count=2, ) print( res24 ) # >>> [ # ['race:italy', [ # ('1692629925789-0', # {'rider': 'Royce'} # ), # ('1692629925790-0', # {'rider': 'Sam-Bodden'} # ) # ] # ] # ] res25 = r.xpending("race:italy", "italy_riders") print( res25 ) # >>> { # 'pending': 2, 'min': '1692629925789-0', 'max': '1692629925790-0', # 'consumers': [{'name': 'Bob', 'pending': 2}] # } res26 = r.xpending_range("race:italy", "italy_riders", "-", "+", 10) print( res26 ) # >>> [ # { # 'message_id': '1692629925789-0', 'consumer': 'Bob', # 'time_since_delivered': 31084, 'times_delivered': 1 # }, # { # 'message_id': '1692629925790-0', 'consumer': 'Bob', # 'time_since_delivered': 31084, 'times_delivered': 1 # } # ] res27 = r.xrange("race:italy", "1692629925789-0", "1692629925789-0") print(res27) # >>> [('1692629925789-0', {'rider': 'Royce'})] res28 = r.xclaim("race:italy", "italy_riders", "Alice", 60000, ["1692629925789-0"]) print(res28) # >>> [('1692629925789-0', {'rider': 'Royce'})] res29 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "0-0", 1) print(res29) # >>> ['1692629925790-0', [('1692629925789-0', {'rider': 'Royce'})]] res30 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "(1692629925789-0", 1) print(res30) # >>> ['0-0', [('1692629925790-0', {'rider': 'Sam-Bodden'})]] res31 = r.xinfo_stream("race:italy") print( res31 ) # >>> { # 'length': 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, # 'last-generated-id': '1692629926436-0', 'groups': 1, # 'first-entry': ('1692629925771-0', {'rider': 'Castilla'}), # 'last-entry': ('1692629926436-0', {'rider': 'Norem'}) # } res32 = r.xinfo_groups("race:italy") print( res32 ) # >>> [ # { # 'name': 'italy_riders', 'consumers': 2, 'pending': 2, # 'last-delivered-id': '1692629925790-0' # } # ] res33 = r.xinfo_consumers("race:italy", "italy_riders") print( res33 ) # >>> [ # {'name': 'Alice', 'pending': 2, 'idle': 199332}, # {'name': 'Bob', 'pending': 0, 'idle': 489170} # ] r.xadd("race:italy", {"rider": "Jones"}, maxlen=2) r.xadd("race:italy", {"rider": "Wood"}, maxlen=2) r.xadd("race:italy", {"rider": "Henshaw"}, maxlen=2) res34 = r.xlen("race:italy") print(res34) # >>> 8 res35 = r.xrange("race:italy", "-", "+") print( res35 ) # >>> [ # ('1692629925771-0', {'rider': 'Castilla'}), # ('1692629925789-0', {'rider': 'Royce'}), # ('1692629925790-0', {'rider': 'Sam-Bodden'}), # ('1692629925791-0', {'rider': 'Prickett'}), # ('1692629926436-0', {'rider': 'Norem'}), # ('1692630612602-0', {'rider': 'Jones'}), # ('1692630641947-0', {'rider': 'Wood'}), # ('1692630648281-0', {'rider': 'Henshaw'}) # ] r.xadd("race:italy", {"rider": "Smith"}, maxlen=2, approximate=False) res36 = r.xrange("race:italy", "-", "+") print( res36 ) # >>> [ # ('1692630648281-0', {'rider': 'Henshaw'}), # ('1692631018238-0', {'rider': 'Smith'}) # ] res37 = r.xtrim("race:italy", maxlen=10, approximate=False) print(res37) # >>> 0 res38 = r.xtrim("race:italy", maxlen=10) print(res38) # >>> 0 res39 = r.xrange("race:italy", "-", "+") print( res39 ) # >>> [ # ('1692630648281-0', {'rider': 'Henshaw'}), # ('1692631018238-0', {'rider': 'Smith'}) # ] res40 = r.xdel("race:italy", "1692631018238-0") print(res40) # >>> 1 res41 = r.xrange("race:italy", "-", "+") print(res41) # >>> [('1692630648281-0', {'rider': 'Henshaw'})]import assert from 'assert'; import { createClient } from 'redis'; const client = await createClient(); await client.connect(); const res1 = await client.xAdd( 'race:france', '*', { 'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1' } ); console.log(res1); // >>> 1700073067968-0 N.B. actual values will differ from these examples const res2 = await client.xAdd( 'race:france', '*', { 'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1' }, ); console.log(res2); // >>> 1692629594113-0 const res3 = await client.xAdd( 'race:france', '*', { 'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1' }, ); console.log(res3); // >>> 1692629613374-0 const res4 = await client.xRange('race:france', '1691765278160-0', '+', {COUNT: 2}); console.log(res4); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] const res5 = await client.xRead({ key: 'race:france', id: '0-0' }, { COUNT: 100, BLOCK: 300 }); console.log(res5); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }] }] const res6 = await client.xAdd( 'race:france', '*', { 'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2' } ); console.log(res6); // >>> 1692629676124-0 const res7 = await client.xLen('race:france'); console.log(res7); // >>> 4 const res8 = await client.xAdd('race:usa', '0-1', { 'racer': 'Castilla' }); console.log(res8); // >>> 0-1 const res9 = await client.xAdd('race:usa', '0-2', { 'racer': 'Norem' }); console.log(res9); // >>> 0-2 try { const res10 = await client.xAdd('race:usa', '0-1', { 'racer': 'Prickett' }); console.log(res10); // >>> 0-1 } catch (error) { console.error(error); // >>> [SimpleError: ERR The ID specified in XADD is equal or smaller than the target stream top item] } const res11a = await client.xAdd('race:usa', '0-*', { racer: 'Norem' }); console.log(res11a); // >>> 0-3 const res11 = await client.xRange('race:france', '-', '+'); console.log(res11); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res12 = await client.xRange('race:france', '1692629576965', '1692629576967'); console.log(res12); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }] const res13 = await client.xRange('race:france', '-', '+', {COUNT: 2}); console.log(res13); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] const res14 = await client.xRange('race:france', '(1692629594113-0', '+', {COUNT: 2}); console.log(res14); // >>> [{ id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res15 = await client.xRange('race:france', '(1692629676124-0', '+', {COUNT: 2}); console.log(res15); // >>> [] const res16 = await client.xRevRange('race:france', '+', '-', {COUNT: 1}); console.log( res16 ); // >>> [{ id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res17 = await client.xRead({ key: 'race:france', id: '0-0' }, { COUNT: 2 }); console.log(res17); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] }] const res18 = await client.xGroupCreate('race:france', 'france_riders', '$'); console.log(res18); // >>> OK const res19 = await client.xGroupCreate('race:italy', 'italy_riders', '$', { MKSTREAM: true }); console.log(res19); // >>> OK await client.xAdd('race:italy', '*', { 'rider': 'Castilla' }); await client.xAdd('race:italy', '*', { 'rider': 'Royce' }); await client.xAdd('race:italy', '*', { 'rider': 'Sam-Bodden' }); await client.xAdd('race:italy', '*', { 'rider': 'Prickett' }); await client.xAdd('race:italy', '*', { 'rider': 'Norem' }); const res20 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '>' }, { COUNT: 1 } ); console.log(res20); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }] const res21 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '0' }, { COUNT: 1 } ); console.log(res21); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }] const res22 = await client.xAck('race:italy', 'italy_riders', '1692629925771-0') console.log(res22); // >>> 1 const res23 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '0' }, { COUNT: 1 } ); console.log(res23); // >>> [{ name: 'race:italy', messages: [] }] const res24 = await client.xReadGroup( 'italy_riders', 'Bob', { key: 'race:italy', id: '>' }, { COUNT: 2 } ); console.log(res24); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }] }] const res25 = await client.xPending('race:italy', 'italy_riders'); console.log(res25); // >>> {'pending': 2, 'firstId': '1692629925789-0', 'lastId': '1692629925790-0', 'consumers': [{'name': 'Bob', 'deliveriesCounter': 2}]} const res26 = await client.xPendingRange('race:italy', 'italy_riders', '-', '+', 10); console.log(res26); // >>> [{'id': '1692629925789-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter:': 1}, {'id': '1692629925790-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter': 1}] const res27 = await client.xRange('race:italy', '1692629925789-0', '1692629925789-0'); console.log(res27); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }] const res28 = await client.xClaim( 'race:italy', 'italy_riders', 'Alice', 60000, ['1692629925789-0'] ); console.log(res28); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }] const res29 = await client.xAutoClaim('race:italy', 'italy_riders', 'Alice', 1, '0-0', { COUNT: 1 }); console.log(res29); // >>> { nextId: '1692629925790-0', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }], deletedMessages: [] } const res30 = await client.xAutoClaim( 'race:italy', 'italy_riders', 'Alice', 1, '(1692629925789-0', { COUNT: 1 } ); console.log(res30); // >>> { nextId: '0-0', messages: [{ id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }], deletedMessages: [] } const res31 = await client.xInfoStream('race:italy'); console.log(res31); // >>> { length: 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, 'last-generated-id': '1692629926436-0', 'max-deleted-entry-id': '0-0', 'entries-added': 5, 'recorded-first-entry-id': '1692629925771-0', groups: 1, 'first-entry': { id: '1692629925771-0', message: { rider: 'Castilla' } }, 'last-entry': { id: '1692629926436-0', message: { rider: 'Norem' } } } const res32 = await client.xInfoGroups('race:italy'); console.log(res32); // >>> [{ name: 'italy_riders', consumers: 2, pending: 3, 'last-delivered-id': '1692629925790-0', 'entries-read': 3, lag: 2 }] const res33 = await client.xInfoConsumers('race:italy', 'italy_riders'); console.log(res33); // >>> [{ name: 'Alice', pending: 3, idle: 170582, inactive: 170582 }, { name: 'Bob', pending: 0, idle: 489404, inactive: 489404 }] await client.xAdd('race:italy', '*', { 'rider': 'Jones' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); await client.xAdd('race:italy', '*', { 'rider': 'Wood' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); await client.xAdd('race:italy', '*', { 'rider': 'Henshaw' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); const res34 = await client.xLen('race:italy'); console.log(res34); // >>> 8 const res35 = await client.xRange('race:italy', '-', '+'); console.log(res35); // >>> [{ id: '1692629925771-0', message: { rider: 'Castilla' } }, { id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }, { id: '1692629925791-0', message: { rider: 'Prickett' } }, { id: '1692629926436-0', message: { rider: 'Norem' } }, { id: '1692630612602-0', message: { rider: 'Jones' } }, { id: '1692630641947-0', message: { rider: 'Wood' } }, { id: '1692630648281-0', message: { rider: 'Henshaw' } }] await client.xAdd('race:italy', '*', { 'rider': 'Smith' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '=', threshold: 2 } }); const res36 = await client.xRange('race:italy', '-', '+'); console.log(res36); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }] const res37 = await client.xTrim('race:italy', 'MAXLEN', 10, { strategyModifier: '=', }); console.log(res37); // >>> 0 const res38 = await client.xTrim('race:italy', "MAXLEN", 10); console.log(res38); // >>> 0 const res39 = await client.xRange('race:italy', '-', '+'); console.log(res39); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }] const res40 = await client.xDel('race:italy', '1692631018238-0'); console.log(res40); // >>> 1 const res41 = await client.xRange('race:italy', '-', '+'); console.log(res41); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }]package io.redis.examples; import redis.clients.jedis.StreamEntryID; import redis.clients.jedis.RedisClient; public class StreamsExample { public void run() { RedisClient jedis = RedisClient.create("redis://localhost:6379"); StreamEntryID res1 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","30.2");put("position","1");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res1); // >>> 1701760582225-0 StreamEntryID res2 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Norem");put("speed","28.8");put("position","3");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res2); // >>> 1701760582225-1 StreamEntryID res3 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Prickett");put("speed","29.7");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res3); // >>> 1701760582226-0 List<StreamEntry> res4 = jedis.xrange("race:france","1701760582225-0","+",2); System.out.println(res4); // >>> [1701760841292-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701760841292-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<Map.Entry<String, List<StreamEntry>>> res5= jedis.xread(XReadParams.xReadParams().block(300).count(100),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}}); System.out.println( res5 ); // >>> [race:france=[1701761996660-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701761996661-0 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701761996661-1 {rider=Prickett, speed=29.7, location_id=1, position=2}]] StreamEntryID res6 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","29.9");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res6); // >>> 1701762285679-0 long res7 = jedis.xlen("race:france"); System.out.println(res7); // >>> 4 StreamEntryID res8 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Castilla");}},XAddParams.xAddParams().id("0-1")); System.out.println(res8); // >>> 0-1 StreamEntryID res9 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-2")); System.out.println(res9); // >>> 0-2 try { StreamEntryID res10 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Prickett");}},XAddParams.xAddParams().id("0-1")); System.out.println(res10); // >>> 0-1 } catch (JedisDataException e){ System.out.println(e); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } StreamEntryID res11 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-*")); System.out.println(res11); List<StreamEntry> res12 = jedis.xrange("race:france","-","+"); System.out.println( res12 ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<StreamEntry> res13 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000),String.valueOf(System.currentTimeMillis()+1000)); System.out.println( res13 ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<StreamEntry> res14 = jedis.xrange("race:france","-","+",2); System.out.println(res14); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<StreamEntry> res15 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000)+"-0","+",2); System.out.println(res15); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<StreamEntry> res16 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()+1000)+"-0","+",2); System.out.println(res16); // >>> [] List<StreamEntry> res17 = jedis.xrevrange("race:france","+","-",1); System.out.println(res17); // >>> [1701765218592-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<Map.Entry<String, List<StreamEntry>>> res18= jedis.xread(XReadParams.xReadParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}}); System.out.println( res18 ); // >>> [race:france=[1701765384638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701765384638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]] String res19 = jedis.xgroupCreate("race:france","france_riders",StreamEntryID.LAST_ENTRY,false); System.out.println(res19); // >>> OK String res20 = jedis.xgroupCreate("race:italy","italy_riders",StreamEntryID.LAST_ENTRY,true); System.out.println(res20); // >>> OK StreamEntryID id1 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Castilaa");}},XAddParams.xAddParams()); StreamEntryID id2 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Royce");}},XAddParams.xAddParams()); StreamEntryID id3 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Sam-Bodden");}},XAddParams.xAddParams()); StreamEntryID id4 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Prickett");}},XAddParams.xAddParams()); StreamEntryID id5 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Norem");}},XAddParams.xAddParams()); List<Map.Entry<String, List<StreamEntry>>> res21 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); System.out.println(res21); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] List<Map.Entry<String, List<StreamEntry>>> res22 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}}); System.out.println(res22); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] long res23 = jedis.xack("race:italy","italy_riders",id1); System.out.println(res23); // >>> 1 List<Map.Entry<String, List<StreamEntry>>> res24 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}}); System.out.println(res24); // >>> [race:italy=[]] List<Map.Entry<String, List<StreamEntry>>> res25 = jedis.xreadGroup("italy_riders","Bob", XReadGroupParams.xReadGroupParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); System.out.println(res25); // >>> [race:italy=[1701767632261-1 {rider=Royce}, 1701767632262-0 {rider=Sam-Bodden}]] StreamPendingSummary res26 = jedis.xpending("race:italy","italy_riders"); System.out.println(res26.getConsumerMessageCount()); // >>> {Bob=2} List<StreamPendingEntry> res27 = jedis.xpending("race:italy","italy_riders",XPendingParams.xPendingParams().start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(10)); System.out.println(res27); // >>> [1701768567412-1 Bob idle:0 times:1, 1701768567412-2 Bob idle:0 times:1] List<StreamEntry> res28 = jedis.xrange("race:italy",id2.toString(),id2.toString()); System.out.println(res28); // >>> [1701768744819-1 {rider=Royce}] List<StreamEntry> res29 = jedis.xclaim("race:italy","italy_riders","Alice", 0L, XClaimParams.xClaimParams().time(60000),id2); System.out.println(res29); // >>> [1701769004195-1 {rider=Royce}] Map.Entry<StreamEntryID, List<StreamEntry>> res30 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID("0-0"),XAutoClaimParams.xAutoClaimParams().count(1)); System.out.println(res30); // >>> [1701769266831-2=[1701769266831-1 {rider=Royce}] Map.Entry<StreamEntryID, List<StreamEntry>> res31 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID(id2.toString()),XAutoClaimParams.xAutoClaimParams().count(1)); System.out.println(res31); // >>> [0-0=[1701769605847-2 {rider=Sam-Bodden}] StreamInfo res32 = jedis.xinfoStream("race:italy"); System.out.println( res32.getStreamInfo() ); // >>> {radix-tree-keys=1, radix-tree-nodes=2, entries-added=5, length=5, groups=1, max-deleted-entry-id=0-0, first-entry=1701769637612-0 {rider=Castilaa}, last-generated-id=1701769637612-4, last-entry=1701769637612-4 {rider=Norem}, recorded-first-entry-id=1701769637612-0} List<StreamGroupInfo> res33 = jedis.xinfoGroups("race:italy"); for (StreamGroupInfo a : res33){ System.out.println( a.getGroupInfo() ); // >>> {last-delivered-id=1701770253659-0, lag=2, pending=2, name=italy_riders, consumers=2, entries-read=3} } List<StreamConsumersInfo> res34 = jedis.xinfoConsumers("race:italy","italy_riders"); for (StreamConsumerInfo a : res34){ System.out.println( a.getConsumerInfo() ); // {inactive=1, idle=1, pending=1, name=Alice} , {inactive=3, idle=3, pending=1, name=Bob} } jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Jones");}},XAddParams.xAddParams().maxLen(10)); jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Wood");}},XAddParams.xAddParams().maxLen(10)); jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Henshaw");}},XAddParams.xAddParams().maxLen(10)); long res35 = jedis.xlen("race:italy"); System.out.println(res35); // >>> 8 List<StreamEntry> res36 = jedis.xrange("race:italy","-","+"); System.out.println(res36); // >>> [1701771219852-0 {rider=Castilaa}, 1701771219852-1 {rider=Royce}, 1701771219853-0 {rider=Sam-Bodden}, 1701771219853-1 {rider=Prickett}, 1701771219853-2 {rider=Norem}, 1701771219858-0 {rider=Jones}, 1701771219858-1 {rider=Wood}, 1701771219859-0 {rider=Henshaw}] StreamEntryID id6 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Smith");}},XAddParams.xAddParams().maxLen(2)); List<StreamEntry> res37 = jedis.xrange("race:italy","-","+"); System.out.println(res37); // >>> [1701771067332-1 {rider=Henshaw}, 1701771067332-2 {rider=Smith}] long res38 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10).exactTrimming()); System.out.println(res38); /// >>> 0 long res39 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10)); System.out.println(res39); /// >>> 0 List<StreamEntry> res40 = jedis.xrange("race:italy","-","+"); System.out.println(res40); // >>> [1701771356428-2 {rider=Henshaw}, 1701771356429-0 {rider=Smith}] long res41 = jedis.xdel("race:italy",id6); System.out.println(res41); // >>> 1 List<StreamEntry> res42 = jedis.xrange("race:italy","-","+"); System.out.println(res42); // >>> [1701771517639-1 {rider=Henshaw}] jedis.close(); } }package example_commands_test import ( "context" "fmt" "github.com/redis/go-redis/v9" ) func ExampleClient_xadd() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res1, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.Println(res1) // >>> 1692632086370-0 res2, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.PrintLn(res2) // >>> 1692632094485-0 res3, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.Println(res3) // >>> 1692632102976-0 xlen, err := rdb.XLen(ctx, "race:france").Result() if err != nil { panic(err) } fmt.Println(xlen) // >>> 3 } func ExampleClient_racefrance1() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, ID: "1692632094485-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, ID: "1692632102976-0", }).Result() if err != nil { panic(err) } res4, err := rdb.XRangeN(ctx, "race:france", "1691765278160-0", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res4) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla... res5, err := rdb.XRead(ctx, &redis.XReadArgs{ Streams: []string{"race:france", "0"}, Count: 100, Block: 300, }).Result() if err != nil { panic(err) } fmt.Println(res5) // >>> // [{race:france [{1692632086370-0 map[location_id:1 position:1... res6, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2, }, }).Result() if err != nil { panic(err) } //fmt.Println(res6) // >>> 1692632147973-0 res7, err := rdb.XLen(ctx, "race:france").Result() if err != nil { panic(err) } fmt.Println(res7) // >>> 4 } func ExampleClient_raceusa() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res8, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Castilla", }, ID: "0-1", }).Result() if err != nil { panic(err) } fmt.Println(res8) // >>> 0-1 res9, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Norem", }, ID: "0-2", }).Result() if err != nil { panic(err) } fmt.Println(res9) // >>> 0-2 res10, err := rdb.XAdd(ctx, &redis.XAddArgs{ Values: map[string]interface{}{ "racer": "Prickett", }, ID: "0-1", }).Result() if err != nil { // fmt.Println(err) // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } res11, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Prickett", }, ID: "0-*", }).Result() if err != nil { panic(err) } fmt.Println(res11) // >>> 0-3 } func ExampleClient_racefrance2() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, ID: "1692632094485-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, ID: "1692632102976-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2, }, ID: "1692632147973-0", }).Result() if err != nil { panic(err) } res12, err := rdb.XRange(ctx, "race:france", "-", "+").Result() if err != nil { panic(err) } fmt.Println(res12) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla... res13, err := rdb.XRange(ctx, "race:france", "1692632086369", "1692632086371", ).Result() if err != nil { panic(err) } fmt.Println(res13) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0}] res14, err := rdb.XRangeN(ctx, "race:france", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res14) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}] res15, err := rdb.XRangeN(ctx, "race:france", "(1692632094485-0", "+", 2, ).Result() if err != nil { panic(err) } fmt.Println(res15) // >>> [{1692632102976-0 map[location_id:1 position:2 rider:Prickett speed:29.7] 0 0} {1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}] res16, err := rdb.XRangeN(ctx, "race:france", "(1692632147973-0", "+", 2, ).Result() if err != nil { panic(err) } fmt.Println(res16) // >>> [] res17, err := rdb.XRevRangeN(ctx, "race:france", "+", "-", 1).Result() if err != nil { panic(err) } fmt.Println(res17) // >>> [{1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}] res18, err := rdb.XRead(ctx, &redis.XReadArgs{ Streams: []string{"race:france", "0"}, Count: 2, }).Result() if err != nil { panic(err) } fmt.Println(res18) // >>> [{race:france [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}]}] } func ExampleClient_xgroupcreate() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } res19, err := rdb.XGroupCreate(ctx, "race:france", "france_riders", "$").Result() if err != nil { panic(err) } fmt.Println(res19) // >>> OK } func ExampleClient_xgroupcreatemkstream() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res20, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } fmt.Println(res20) // >>> OK } func ExampleClient_xgroupread() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Castilla"}, }).Result() // >>> 1692632639151-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Royce"}, }).Result() // >>> 1692632647899-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Sam-Bodden"}, }).Result() // >>> 1692632662819-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Prickett"}, }).Result() // >>> 1692632670501-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Norem"}, }).Result() // >>> 1692632678249-0 if err != nil { panic(err) } // fmt.Println(res25) res21, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Alice", Count: 1, }).Result() if err != nil { panic(err) } // fmt.Println(res21) // >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}] xlen, err := rdb.XLen(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(xlen) } func ExampleClient_raceitaly() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Castilla"}, ID: "1692632639151-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Royce"}, ID: "1692632647899-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Sam-Bodden"}, ID: "1692632662819-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Prickett"}, ID: "1692632670501-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Norem"}, ID: "1692632678249-0", }).Result() if err != nil { panic(err) } _, err = rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Alice", Count: 1, }).Result() if err != nil { panic(err) } res22, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", "0"}, Group: "italy_riders", Consumer: "Alice", }).Result() if err != nil { panic(err) } fmt.Println(res22) // >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}] res23, err := rdb.XAck(ctx, "race:italy", "italy_riders", "1692632639151-0", ).Result() if err != nil { panic(err) } fmt.Println(res23) // >>> 1 res24, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", "0"}, Group: "italy_riders", Consumer: "Alice", }).Result() if err != nil { panic(err) } fmt.Println(res24) // >>> [{race:italy []}] res25, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Bob", Count: 2, }).Result() if err != nil { panic(err) } fmt.Println(res25) // >>> [{race:italy [{1692632647899-0 map[rider:Royce] 0 0} {1692632662819-0 map[rider:Sam-Bodden] 0 0}]}] res26, err := rdb.XPending(ctx, "race:italy", "italy_riders").Result() if err != nil { panic(err) } fmt.Println(res26) // >>> &{2 1692632647899-0 1692632662819-0 map[Bob:2]} res27, err := rdb.XPendingExt(ctx, &redis.XPendingExtArgs{ Stream: "race:italy", Group: "italy_riders", Start: "-", End: "+", Count: 10, }).Result() if err != nil { panic(err) } // fmt.Println(res27) // >>> [{1692632647899-0 Bob 0s 1} {1692632662819-0 Bob 0s 1}] res28, err := rdb.XRange(ctx, "race:italy", "1692632647899-0", "1692632647899-0", ).Result() if err != nil { panic(err) } fmt.Println(res28) // >>> [{1692632647899-0 map[rider:Royce] 0 0}] res29, err := rdb.XClaim(ctx, &redis.XClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Alice", MinIdle: 0, Messages: []string{"1692632647899-0"}, }).Result() if err != nil { panic(err) } fmt.Println(res29) res30, res30a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Alice", Start: "0-0", Count: 1, }).Result() if err != nil { panic(err) } fmt.Println(res30) // >>> [{1692632647899-0 map[rider:Royce] 0 0}] fmt.Println(res30a) // >>> 1692632662819-0 res31, res31a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Lora", Start: "(1692632662819-0", Count: 1, }).Result() if err != nil { panic(err) } fmt.Println(res31) // >>> [] fmt.Println(res31a) // >>> 0-0 res32, err := rdb.XInfoStream(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res32.Length) // >>> 5 fmt.Println(res32.FirstEntry) // >>> {1692632639151-0 map[rider:Castilla] 0 0} res33, err := rdb.XInfoGroups(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res33) // >>> [{italy_riders 3 2 1692632662819-0 3 2}] res34, err := rdb.XInfoConsumers(ctx, "race:italy", "italy_riders").Result() if err != nil { panic(err) } // fmt.Println(res34) // >>> [{Alice 1 1ms 1ms} {Bob 1 2ms 2ms} {Lora 0 1ms -1ms}] _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Jones"}, }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Wood"}, }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Henshaw"}, }, ).Result() if err != nil { panic(err) } res35, err := rdb.XLen(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res35) // >>> 2 res36, err := rdb.XRange(ctx, "race:italy", "-", "+").Result() if err != nil { panic(err) } // fmt.Println(res36) // >>> [{1726649529170-1 map[rider:Wood] 0 0} {1726649529171-0 map[rider:Henshaw] 0 0}] res37, err := rdb.XTrimMaxLen(ctx, "race:italy", 10).Result() if err != nil { panic(err) } fmt.Println(res37) // >>> 0 res38, err := rdb.XTrimMaxLenApprox(ctx, "race:italy", 10, 20).Result() if err != nil { panic(err) } fmt.Println(res38) // >>> 0 } func ExampleClient_xdel() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Wood"}, ID: "1692633198206-0", }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Henshaw"}, ID: "1692633208557-0", }, ).Result() if err != nil { panic(err) } res39, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res39) // >>> [{1692633198206-0 map[rider:Wood] 0 0} {1692633208557-0 map[rider:Henshaw] 0 0}] res40, err := rdb.XDel(ctx, "race:italy", "1692633208557-0").Result() if err != nil { panic(err) } fmt.Println(res40) // 1 res41, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res41) // >>> [{1692633198206-0 map[rider:Wood] 0 0}] }using NRedisStack.Tests; using StackExchange.Redis; public class StreamTutorial { public void Run() { var muxer = ConnectionMultiplexer.Connect("localhost:6379"); var db = muxer.GetDatabase(); RedisValue res1 = db.StreamAdd( "race:france", [ new("rider", "Castilla"), new("speed", 30.2), new("position", 1), new("location_id", 1) ] ); Console.WriteLine(res1); // >>> 1712668482289-0 RedisValue res2 = db.StreamAdd( "race:france", [ new("rider", "Norem"), new("speed", 28.8), new("position", 3), new("location_id", 1) ] ); Console.WriteLine(res2); // >>> 1712668766534-1 RedisValue res3 = db.StreamAdd( "race:france", [ new("rider", "Prickett"), new("speed", 29.7), new("position", 2), new("location_id", 1) ] ); Console.WriteLine(res3); // >>> 1712669055705-0 // Tests for 'xadd' step. StreamEntry[] res4 = db.StreamRange("race:france", "1712668482289-0", "+", 2); foreach (StreamEntry entry in res4) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xrange' step. StreamEntry[] res5 = db.StreamRead("race:france", 0, 100); foreach (StreamEntry entry in res4) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // Tests for 'xread_block' step. RedisValue res6 = db.StreamAdd( "race:france", [ new("rider", "Castilla"), new("speed", 29.9), new("position", 1), new("location_id", 2) ] ); Console.WriteLine(res6); // >>> 1712675674750-0 // Tests for 'xadd_2' step. long res7 = db.StreamLength("race:france"); Console.WriteLine(res7); // >>> 4 // Tests for 'xlen' step. RedisValue res8 = db.StreamAdd( "race:usa", [ new("racer", "Castilla") ], "0-1" ); Console.WriteLine(res8); // >>> 0-1 RedisValue res9 = db.StreamAdd( "race:usa", [ new("racer", "Norem") ], "0-2" ); Console.WriteLine(res9); // >>> 0-2 // Tests for 'xadd_id' step. try { RedisValue res10 = db.StreamAdd( "race:usa", [ new("racer", "Prickett") ], "0-1" ); } catch (RedisServerException ex) { Console.WriteLine(ex); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } // Tests for 'xadd_bad_id' step. RedisValue res11 = ""; Version version = muxer.GetServer("localhost:6379").Version; if (version.Major >= 7) { res11 = db.StreamAdd( "race:usa", [ new("rider", "Norem") ], "0-*" ); Console.WriteLine(res11); // >>> "0-3" } // Tests for 'xadd_7' step. StreamEntry[] res12 = db.StreamRange("race:france", "-", "+"); foreach (StreamEntry entry in res12) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrange_all' step. StreamEntry[] res13 = db.StreamRange("race:france", 1712668482289, 1712668482291); foreach (StreamEntry entry in res13) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // Tests for 'xrange_time' step. StreamEntry[] res14 = db.StreamRange("race:france", "-", "+", 2); foreach (StreamEntry entry in res14) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xrange_step_1' step. StreamEntry[] res15 = db.StreamRange("race:france", "(1712668766534-1", "+", 2); foreach (StreamEntry entry in res15) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrange_step_2' step. StreamEntry[] res16 = db.StreamRange("race:france", "(1712675674750-0", "+", 2); foreach (StreamEntry entry in res16) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> <empty array> // Tests for 'xrange_empty' step. StreamEntry[] res17 = db.StreamRange("race:france", "+", "-", 1, Order.Descending); foreach (StreamEntry entry in res17) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrevrange' step. StreamEntry[] res18 = db.StreamRead("race:france", 0, 2); foreach (StreamEntry entry in res18) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xread' step. bool res19 = db.StreamCreateConsumerGroup("race:france", "france_riders", "$"); Console.WriteLine(res19); // >>> true // Tests for 'xgroup_create' step. bool res20 = db.StreamCreateConsumerGroup("race:italy", "italy_riders", "$", true); Console.WriteLine(res20); // >>> true // Tests for 'xgroup_create_mkstream' step. RedisValue groupRes = db.StreamAdd( "race:italy", [new("rider", "Castilla")] ); // 1712744323758-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Royce")] ); // 1712744358384-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Sam-Bodden")] ); // 1712744379676-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Prickett")] ); // 1712744399401-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Norem")] ); // 1712744413117-0 StreamEntry[] res21 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", ">", 1); foreach (StreamEntry entry in res21) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744323758-0: [rider: Castilla] // Tests for 'xgroup_read' step. StreamEntry[] res22 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0"); foreach (StreamEntry entry in res22) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); // >>> 1712744323758-0: [rider: Castilla] } // Tests for 'xgroup_read_id' step. long res23 = db.StreamAcknowledge("race:italy", "italy_riders", "1712744323758-0"); Console.WriteLine(res23); // >>> 1 StreamEntry[] res24 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0"); foreach (StreamEntry entry in res24) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> <empty array> // Tests for 'xack' step. StreamEntry[] res25 = db.StreamReadGroup("race:italy", "italy_riders", "Bob", ">", 2); foreach (StreamEntry entry in res25) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // >>> 1712744379676-0: [rider: Sam-Bodden] // Tests for 'xgroup_read_bob' step. StreamPendingInfo res26 = db.StreamPending("race:italy", "italy_riders"); Console.WriteLine($"pending: {res26.PendingMessageCount}, min: {res26.LowestPendingMessageId}, max: {res26.HighestPendingMessageId}, consumers:[{string.Join(", ", res26.Consumers.Select(c => $"{c.Name}: {c.PendingMessageCount}"))}]"); // >>> pending: 2, min: 1712747506906-0, max: 1712747506907-0, consumers:[name: Bob, pending:2] // Tests for 'xpending' step. StreamPendingMessageInfo[] res27 = db.StreamPendingMessages( "race:italy", "italy_riders", 10, "", "-", "+" ); foreach (StreamPendingMessageInfo info in res27) { Console.WriteLine($"message_id: {info.MessageId}, consumer: {info.ConsumerName}, time_since_delivered: {info.IdleTimeInMilliseconds}, times_delivered: {info.DeliveryCount}"); } // >>> message_id: min: 1712747506906-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1 // >>> message_id: min: 1712747506907-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1 // Tests for 'xpending_plus_minus' step. StreamEntry[] res28 = db.StreamRange("race:italy", "1712744358384-0", "1712744358384-0"); foreach (StreamEntry entry in res28) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // Tests for 'xrange_pending' step. StreamEntry[] res29 = db.StreamClaim( "race:italy", "italy_riders", "Alice", 60000, [1712744358384 - 0] ); foreach (StreamEntry entry in res29) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // Tests for 'xclaim' step. StreamAutoClaimResult res30 = db.StreamAutoClaim( "race:italy", "italy_riders", "Alice", 1, "0-0", 1 ); Console.WriteLine($"{res30.NextStartId}, ({string.Join(", ", res30.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})"); // >>> 1712744379676-0, (1712744358384-0: [rider: Royce]) // Tests for 'xautoclaim' step. StreamAutoClaimResult res31 = db.StreamAutoClaim( "race:italy", "italy_riders", "Alice", 1, "(1712744358384-0", 1 ); Console.WriteLine($"{res31.NextStartId}, ({string.Join(", ", res31.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})"); // >>> 0-0, (1712744379676-0: [rider: Sam-Bodden]) // Tests for 'xautoclaim_cursor' step. StreamInfo res32 = db.StreamInfo("race:italy"); Console.WriteLine($"length: {res32.Length}, radix-tree-keys: {res32.RadixTreeKeys}, radix-tree-nodes: {res32.RadixTreeNodes}, last-generated-id: {res32.LastGeneratedId}, first-entry: {$"{res32.FirstEntry.Id}: [{string.Join(", ", res32.FirstEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}, last-entry: {$"{res32.LastEntry.Id}: [{string.Join(", ", res32.LastEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}"); // >>> length: 5, radix-tree-keys: 1, radix-tree-nodes: 2, last-generated-id: 1712756762686-1, first-entry: 1712756762685-0: [rider: Castilla], last-entry: 1712756762686-1: [rider: Norem] // Tests for 'xinfo' step. StreamGroupInfo[] res33 = db.StreamGroupInfo("race:italy"); foreach (StreamGroupInfo info in res33) { Console.WriteLine($"name: {info.Name}, consumers: {info.ConsumerCount}, pending: {info.PendingMessageCount}, last-delivered-id: {info.LastDeliveredId}"); } // >>> name: italy_riders, consumers: 2, pending: 2, last-delivered-id: 1712757192730-2 // Tests for 'xinfo_groups' step. StreamConsumerInfo[] res34 = db.StreamConsumerInfo("race:italy", "italy_riders"); foreach (StreamConsumerInfo info in res34) { Console.WriteLine($"name: {info.Name}, pending: {info.PendingMessageCount}, idle: {info.IdleTimeInMilliseconds}"); } // >>> name: Alice, pending: 1, idle: 7717 // >>> name: Bob, pending: 0, idle: 7722 // Tests for 'xinfo_consumers' step. db.StreamAdd( "race:italy", [new("rider", "Jones")], null, 2, true ); db.StreamAdd( "race:italy", [new("rider", "Wood")], null, 2, true ); db.StreamAdd( "race:italy", [new("rider", "Henshaw")], null, 2, true ); long res35 = db.StreamLength("race:italy"); Console.WriteLine(res35); // >>> 8 StreamEntry[] res36 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res36) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712758336128-0: [rider: Castilla] // >>> 1712758336128-1: [rider: Royce] // >>> 1712758336128-2: [rider: Sam-Bodden] // >>> 1712758336129-0: [rider: Prickett] // >>> 1712758336139-0: [rider: Norem] // >>> 1712758340854-0: [rider: Jones] // >>> 1712758341645-0: [rider: Wood] // >>> 1712758342134-0: [rider: Henshaw] db.StreamAdd( "race:italy", [new("rider", "Smith")], null, 2, false ); StreamEntry[] res37 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res37) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // 1712758746476-1: [rider: Henshaw] // 1712758746477-0: [rider: Smith] // Tests for 'maxlen' step. long res38 = db.StreamTrim("race:italy", 10, false); Console.WriteLine(res38); // >>> 0 // Tests for 'xtrim' step. long res39 = db.StreamTrim("race:italy", 10, true); Console.WriteLine(res39); // >>> 0 // Tests for 'xtrim2' step. StreamEntry[] res40 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res40) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712759694003-0: [rider: Henshaw] // >>> 1712759694003-1: [rider: Smith] long res41 = db.StreamDelete("race:italy", ["1712759694003-1"]); Console.WriteLine(res41); // >>> 1 StreamEntry[] res42 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res42) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712759694003-0: [rider: Henshaw] // Tests for 'xdel' step. } }require 'redis' r = Redis.new res1 = r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => 30.2, 'position' => 1, 'location_id' => 1 }) puts res1 # 1692632086370-0, for example res2 = r.xadd('race:france', { 'rider' => 'Norem', 'speed' => 28.8, 'position' => 3, 'location_id' => 1 }) puts res2 # 1692632094485-0, for example res3 = r.xadd('race:france', { 'rider' => 'Prickett', 'speed' => 29.7, 'position' => 2, 'location_id' => 1 }) puts res3 # 1692632102976-0, for example r.del('race:france') r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1' }, id: '1692632086370-0') r.xadd('race:france', { 'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1' }, id: '1692632094485-0') r.xadd('race:france', { 'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1' }, id: '1692632102976-0') r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2' }, id: '1692632147973-0') res4 = r.xrange('race:france', '1692632086370-0', '+', count: 2) puts res4.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') res5 = r.xread(['race:france'], ['$'], count: 100, block: 300) puts res5.inspect # {} res6 = r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => 29.9, 'position' => 1, 'location_id' => 2 }) puts res6 # 1692632147973-0, for example r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632147973-0') res7 = r.xlen('race:france') puts res7 # 4 r.del('race:usa') res8 = r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1') puts res8 # 0-1 res9 = r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2') puts res9 # 0-2 begin r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-1') rescue Redis::CommandError => e puts e.message # ERR The ID specified in XADD is equal or smaller than the target stream top item end r.del('race:usa') r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1') r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2') res10 = r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-*') puts res10 # 0-3 r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res11 = r.xrange('race:france', '-', '+') puts res11.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}], # ["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}], # ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') res12 = r.xrange('race:france', '1692632086369', '1692632086371') puts res12.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res13 = r.xrange('race:france', '-', '+', count: 2) puts res13.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res14 = r.xrange('race:france', '(1692632094485-0', '+', count: 2) puts res14.inspect # [["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}], # ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] res15 = r.xrange('race:france', '(1692632147973-0', '+', count: 2) puts res15.inspect # [] res16 = r.xrevrange('race:france', '+', '-', count: 1) puts res16.inspect # [["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] res17 = r.xread(['race:france'], ['0'], count: 2) puts res17.inspect # {"race:france"=>[["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]]} r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') res18 = r.xgroup(:create, 'race:france', 'france_riders', '$') puts res18 # OK r.del('race:italy') res19 = r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true) puts res19 # OK r.del('race:italy') r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true) r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0') r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0') r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0') r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0') r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0') res20 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['>'], count: 1) puts res20.inspect # {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]} res21 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0'], count: 1) puts res21.inspect # {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]} res22 = r.xack('race:italy', 'italy_riders', '1692632639151-0') puts res22 # 1 res23 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0']) puts res23.inspect # {"race:italy"=>[]} res24 = r.xreadgroup('italy_riders', 'Bob', ['race:italy'], ['>'], count: 2) puts res24.inspect # {"race:italy"=>[["1692632647899-0", {"rider"=>"Royce"}], # ["1692632662819-0", {"rider"=>"Sam-Bodden"}]]} res25 = r.xpending('race:italy', 'italy_riders') puts res25.inspect # {"size"=>2, "min_entry_id"=>"1692632647899-0", "max_entry_id"=>"1692632662819-0", "consumers"=>{"Bob"=>"2"}} res26 = r.xpending('race:italy', 'italy_riders', '-', '+', 10) puts res26.inspect res27 = r.xrange('race:italy', '1692632647899-0', '1692632647899-0') puts res27.inspect # [["1692632647899-0", {"rider"=>"Royce"}]] res28 = r.xclaim('race:italy', 'italy_riders', 'Alice', 0, '1692632647899-0') puts res28.inspect # [["1692632647899-0", {"rider"=>"Royce"}]] res29 = r.xautoclaim('race:italy', 'italy_riders', 'Alice', 0, '0-0', count: 1) puts res29.inspect # {"next"=>"1692632662819-0", "entries"=>[["1692632647899-0", {"rider"=>"Royce"}]]} res30 = r.xautoclaim('race:italy', 'italy_riders', 'Lora', 0, res29['next'], count: 1) puts res30.inspect # {"next"=>"0-0", "entries"=>[["1692632662819-0", {"rider"=>"Sam-Bodden"}]]} res31 = r.xinfo(:stream, 'race:italy') puts res31.inspect res32 = r.xinfo(:groups, 'race:italy') puts res32.inspect res33 = r.xinfo(:consumers, 'race:italy', 'italy_riders') puts res33.inspect r.del('race:italy') r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0') r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0') r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0') r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0') r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0') r.xadd('race:italy', {'rider' => 'Jones'}, id: '1692633189161-0', maxlen: 2) r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0', maxlen: 2) r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0', maxlen: 2) res34 = r.xlen('race:italy') puts res34 # 2 res35 = r.xrange('race:italy', '-', '+') puts res35.inspect # [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]] res36 = r.xtrim('race:italy', 10, approximate: false) puts res36 # 0 r.del('mystream') 1.upto(10) do |n| r.xadd('mystream', {'field' => 'value'}, id: "#{n}-0") end res37 = r.xtrim('mystream', 10, approximate: true) puts res37 # 0 r.del('race:italy') r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0') r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0') res38 = r.xrange('race:italy', '-', '+', count: 2) puts res38.inspect # [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]] res39 = r.xdel('race:italy', '1692633208557-0') puts res39 # 1 res40 = r.xrange('race:italy', '-', '+', count: 2) puts res40.inspect # [["1692633198206-0", {"rider"=>"Wood"}]]mod stream_tests { use redis::{ streams::{ StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply, StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply, StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode, StreamTrimOptions, }, Commands, }; use std::{thread::sleep, time::Duration}; fn delete_keys(r: &mut redis::Connection, keys: &[&str]) { let _: usize = r.del(keys).unwrap_or(0); } fn add_france_fixed(r: &mut redis::Connection) { delete_keys(r, &["race:france"]); let _: Option<String> = r .xadd( "race:france", "1692632086370-0", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .expect("add france 1"); let _: Option<String> = r .xadd( "race:france", "1692632094485-0", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .expect("add france 2"); let _: Option<String> = r .xadd( "race:france", "1692632102976-0", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .expect("add france 3"); let _: Option<String> = r .xadd( "race:france", "1692632147973-0", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .expect("add france 4"); } fn seed_usa_fixed(r: &mut redis::Connection) { delete_keys(r, &["race:usa"]); let _: Option<String> = r .xadd("race:usa", "0-1", &[("racer", "Castilla")]) .expect("add usa 1"); let _: Option<String> = r .xadd("race:usa", "0-2", &[("racer", "Norem")]) .expect("add usa 2"); } fn seed_italy_group_base(r: &mut redis::Connection) { delete_keys(r, &["race:italy"]); let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .expect("create italy group"); let _: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .expect("add italy 1"); let _: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .expect("add italy 2"); let _: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .expect("add italy 3"); let _: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .expect("add italy 4"); let _: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .expect("add italy 5"); } fn seed_italy_alice_pending(r: &mut redis::Connection) { seed_italy_group_base(r); let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .expect("alice read pending"); } fn seed_italy_after_ack(r: &mut redis::Connection) { seed_italy_alice_pending(r); let _: usize = r .xack("race:italy", "italy_riders", &["1692632639151-0"]) .expect("ack first italy message"); } fn seed_italy_bob_pending(r: &mut redis::Connection) { seed_italy_after_ack(r); let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .expect("bob read pending"); } fn seed_italy_info_state(r: &mut redis::Connection) { seed_italy_bob_pending(r); sleep(Duration::from_millis(5)); let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .expect("alice claim"); sleep(Duration::from_millis(5)); let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"]) .expect("lora claim"); } fn seed_trim_stream(r: &mut redis::Connection) { delete_keys(r, &["mystream"]); for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] { let _: Option<String> = r .xadd("mystream", id, &[("field", "value")]) .expect("seed mystream"); } } fn run() { let mut r = match redis::Client::open("redis://127.0.0.1") { Ok(client) => match client.get_connection() { Ok(conn) => conn, Err(e) => { println!("Failed to connect to Redis: {e}"); return; } }, Err(e) => { println!("Failed to create Redis client: {e}"); return; } }; let res1 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .expect("xadd 1"); res.expect("missing stream id") }; println!("{res1}"); // >>> 1692632086370-0 let res2 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .expect("xadd 2"); res.expect("missing stream id") }; println!("{res2}"); // >>> 1692632094485-0 let res3 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .expect("xadd 3"); res.expect("missing stream id") }; println!("{res3}"); // >>> 1692632102976-0 add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r); let opts = StreamReadOptions::default().count(100).block(300); if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts) { let res: Option<StreamReadReply> = res; println!("{res:?}"); // >>> None } if let Ok(res) = r.xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 1692632147973-0 } add_france_fixed(&mut r); if let Ok(res) = r.xlen("race:france") { let res: usize = res; println!("{res}"); // >>> 4 } delete_keys(&mut r, &["race:usa"]); if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-1 } if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-2 } let res: redis::RedisResult<Option<String>> = r.xadd("race:usa", "0-1", &[("racer", "Prickett")]); match res { Ok(_) => {} Err(e) => { let msg = e.to_string(); println!("{msg}"); // >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item } } seed_usa_fixed(&mut r); if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-3 } add_france_fixed(&mut r); if let Ok(res) = r.xrange_all("race:france") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [] } add_france_fixed(&mut r); if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); let opts = StreamReadOptions::default().count(2); if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let reply = res.expect("xread should return data"); let view: Vec<_> = reply .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])] } add_france_fixed(&mut r); if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$") { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]); if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$") { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]); let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .expect("create italy group"); let italy_1: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .expect("italy1"); let italy_1 = italy_1.expect("missing stream id"); println!("{italy_1}"); // >>> 1692632639151-0 let italy_2: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .expect("italy2"); let italy_2 = italy_2.expect("missing stream id"); println!("{italy_2}"); // >>> 1692632647899-0 let italy_3: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .expect("italy3"); let italy_3 = italy_3.expect("missing stream id"); println!("{italy_3}"); // >>> 1692632662819-0 let italy_4: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .expect("italy4"); let italy_4 = italy_4.expect("missing stream id"); println!("{italy_4}"); // >>> 1692632670501-0 let italy_5: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .expect("italy5"); let italy_5 = italy_5.expect("missing stream id"); println!("{italy_5}"); // >>> 1692632678249-0 let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup read should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r); let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r); if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]) { let res: usize = res; println!("{res}"); // >>> 1 } let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [])] } seed_italy_after_ack(&mut r); let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("bob should receive data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])] } seed_italy_bob_pending(&mut r); if let Ok(res) = r.xpending("race:italy", "italy_riders") { let res: StreamPendingReply = res; let view = match res { StreamPendingReply::Empty => None, StreamPendingReply::Data(data) => Some(( data.count, data.start_id.clone(), data.end_id.clone(), data.consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending)) .collect::<Vec<_>>(), )), } .expect("pending summary"); println!("{view:?}"); // >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)]) } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10) { let res: StreamPendingCountReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), entry.consumer.clone(), entry.last_delivered_ms, entry.times_delivered, ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)] } seed_italy_bob_pending(&mut r); if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); if let Ok(res) = r.xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) { let res: redis::streams::StreamClaimReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); let opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r.xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts) { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])]) } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); let first_opts = StreamAutoClaimOptions::default().count(1); let _: redis::streams::StreamAutoClaimReply = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts) .expect("first autoclaim"); let next_opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r.xautoclaim_options( "race:italy", "italy_riders", "Lora", 1, "(1692632647899-0", next_opts, ) { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])]) } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_stream("race:italy") { let res: StreamInfoStreamReply = res; let view = ( res.length, res.radix_tree_keys, res.groups, res.last_generated_id.clone(), res.first_entry.id.clone(), res.last_entry.id.clone(), ); println!("{view:?}"); // >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0") } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_groups("race:italy") { let res: StreamInfoGroupsReply = res; let view: Vec<_> = res .groups .iter() .map(|group| { ( group.name.clone(), group.consumers, group.pending, group.last_delivered_id.clone(), ) }) .collect(); println!("{view:?}"); // >>> [("italy_riders", 3, 2, "1692632662819-0")] } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders") { let res: StreamInfoConsumersReply = res; let mut view: Vec<_> = res .consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle)) .collect(); view.sort_by(|a, b| a.0.cmp(&b.0)); println!("{view:?}"); // >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)] } delete_keys(&mut r, &["race:italy"]); let max1: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")]) .expect("maxlen add 1"); let max1 = max1.expect("missing stream id"); println!("{max1}"); // >>> 1-0 let max2: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")]) .expect("maxlen add 2"); let max2 = max2.expect("missing stream id"); println!("{max2}"); // >>> 2-0 let max3: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")]) .expect("maxlen add 3"); let max3 = max3.expect("missing stream id"); println!("{max3}"); // >>> 3-0 if let Ok(res) = r.xlen("race:italy") { let res: usize = res; println!("{res}"); // >>> 2 } if let Ok(res) = r.xrange_all("race:italy") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } delete_keys(&mut r, &["race:italy"]); let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).expect("trim seed 1"); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).expect("trim seed 2"); if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)) { let res: usize = res; println!("{res}"); // >>> 0 } seed_trim_stream(&mut r); if let Ok(res) = r.xtrim_options( "mystream", &StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10), ) { let res: usize = res; println!("{res}"); // >>> 0 } delete_keys(&mut r, &["race:italy"]); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).expect("xdel seed 1"); let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).expect("xdel seed 2"); if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } if let Ok(res) = r.xdel("race:italy", &["3-0"]) { let res: usize = res; println!("{res}"); // >>> 1 } if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])] } } }mod tests { use redis::{ streams::{ StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply, StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply, StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode, StreamTrimOptions, }, AsyncCommands, }; use tokio::time::{sleep, Duration}; async fn delete_keys(r: &mut redis::aio::MultiplexedConnection, keys: &[&str]) { let _: usize = r.del(keys).await.unwrap_or(0); } async fn add_france_fixed(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:france"]).await; let _: Option<String> = r .xadd( "race:france", "1692632086370-0", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .await .expect("add france 1"); let _: Option<String> = r .xadd( "race:france", "1692632094485-0", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .await .expect("add france 2"); let _: Option<String> = r .xadd( "race:france", "1692632102976-0", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .await .expect("add france 3"); let _: Option<String> = r .xadd( "race:france", "1692632147973-0", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .await .expect("add france 4"); } async fn seed_usa_fixed(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:usa"]).await; let _: Option<String> = r .xadd("race:usa", "0-1", &[("racer", "Castilla")]) .await .expect("add usa 1"); let _: Option<String> = r .xadd("race:usa", "0-2", &[("racer", "Norem")]) .await .expect("add usa 2"); } async fn seed_italy_group_base(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:italy"]).await; let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .await .expect("create italy group"); let _: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .await .expect("add italy 1"); let _: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .await .expect("add italy 2"); let _: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .await .expect("add italy 3"); let _: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .await .expect("add italy 4"); let _: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .await .expect("add italy 5"); } async fn seed_italy_alice_pending(r: &mut redis::aio::MultiplexedConnection) { seed_italy_group_base(r).await; let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .await .expect("alice read pending"); } async fn seed_italy_after_ack(r: &mut redis::aio::MultiplexedConnection) { seed_italy_alice_pending(r).await; let _: usize = r .xack("race:italy", "italy_riders", &["1692632639151-0"]) .await .expect("ack first italy message"); } async fn seed_italy_bob_pending(r: &mut redis::aio::MultiplexedConnection) { seed_italy_after_ack(r).await; let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .await .expect("bob read pending"); } async fn seed_italy_info_state(r: &mut redis::aio::MultiplexedConnection) { seed_italy_bob_pending(r).await; sleep(Duration::from_millis(5)).await; let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .await .expect("alice claim"); sleep(Duration::from_millis(5)).await; let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"]) .await .expect("lora claim"); } async fn seed_trim_stream(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["mystream"]).await; for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] { let _: Option<String> = r .xadd("mystream", id, &[("field", "value")]) .await .expect("seed mystream"); } } async fn run() { let mut r = match redis::Client::open("redis://127.0.0.1") { Ok(client) => match client.get_multiplexed_async_connection().await { Ok(conn) => conn, Err(e) => { println!("Failed to connect to Redis: {e}"); return; } }, Err(e) => { println!("Failed to create Redis client: {e}"); return; } }; let res1: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .await .expect("xadd 1"); let res1 = res1.expect("missing stream id"); println!("{res1}"); // >>> 1692632086370-0 let res2: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .await .expect("xadd 2"); let res2 = res2.expect("missing stream id"); println!("{res2}"); // >>> 1692632094485-0 let res3: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .await .expect("xadd 3"); let res3 = res3.expect("missing stream id"); println!("{res3}"); // >>> 1692632102976-0 add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r).await; let opts = StreamReadOptions::default().count(100).block(300); if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts).await { let res: Option<StreamReadReply> = res; println!("{res:?}"); // >>> None } if let Ok(res) = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 1692632147973-0 } add_france_fixed(&mut r).await; if let Ok(res) = r.xlen("race:france").await { let res: usize = res; println!("{res}"); // >>> 4 } delete_keys(&mut r, &["race:usa"]).await; if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-1 } if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-2 } let res: redis::RedisResult<Option<String>> = r.xadd("race:usa", "0-1", &[("racer", "Prickett")]).await; match res { Ok(_) => {} Err(e) => { let msg = e.to_string(); println!("{msg}"); // >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item } } seed_usa_fixed(&mut r).await; if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-3 } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_all("race:france").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; let opts = StreamReadOptions::default().count(2); if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xread should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$").await { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]).await; if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$").await { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]).await; let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .await .expect("create italy group"); let italy_1: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .await .expect("italy1"); let italy_1 = italy_1.expect("missing stream id"); println!("{italy_1}"); // >>> 1692632639151-0 let italy_2: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .await .expect("italy2"); let italy_2 = italy_2.expect("missing stream id"); println!("{italy_2}"); // >>> 1692632647899-0 let italy_3: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .await .expect("italy3"); let italy_3 = italy_3.expect("missing stream id"); println!("{italy_3}"); // >>> 1692632662819-0 let italy_4: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .await .expect("italy4"); let italy_4 = italy_4.expect("missing stream id"); println!("{italy_4}"); // >>> 1692632670501-0 let italy_5: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .await .expect("italy5"); let italy_5 = italy_5.expect("missing stream id"); println!("{italy_5}"); // >>> 1692632678249-0 let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup read should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r).await; let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r).await; if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]).await { let res: usize = res; println!("{res}"); // >>> 1 } let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [])] } seed_italy_after_ack(&mut r).await; let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("bob should receive data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])] } seed_italy_bob_pending(&mut r).await; if let Ok(res) = r.xpending("race:italy", "italy_riders").await { let res: StreamPendingReply = res; let view = match res { StreamPendingReply::Empty => None, StreamPendingReply::Data(data) => Some(( data.count, data.start_id.clone(), data.end_id.clone(), data.consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending)) .collect::<Vec<_>>(), )), } .expect("pending summary"); println!("{view:?}"); // >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)]) } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10).await { let res: StreamPendingCountReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), entry.consumer.clone(), entry.last_delivered_ms, entry.times_delivered, ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)] } seed_italy_bob_pending(&mut r).await; if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; if let Ok(res) = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .await { let res: redis::streams::StreamClaimReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; let opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts) .await { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])]) } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; let first_opts = StreamAutoClaimOptions::default().count(1); let _: redis::streams::StreamAutoClaimReply = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts) .await .expect("first autoclaim"); let next_opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r .xautoclaim_options( "race:italy", "italy_riders", "Lora", 1, "(1692632647899-0", next_opts, ) .await { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])]) } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_stream("race:italy").await { let res: StreamInfoStreamReply = res; let view = ( res.length, res.radix_tree_keys, res.groups, res.last_generated_id.clone(), res.first_entry.id.clone(), res.last_entry.id.clone(), ); println!("{view:?}"); // >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0") } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_groups("race:italy").await { let res: StreamInfoGroupsReply = res; let view: Vec<_> = res .groups .iter() .map(|group| { ( group.name.clone(), group.consumers, group.pending, group.last_delivered_id.clone(), ) }) .collect(); println!("{view:?}"); // >>> [("italy_riders", 3, 2, "1692632662819-0")] } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders").await { let res: StreamInfoConsumersReply = res; let mut view: Vec<_> = res .consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle)) .collect(); view.sort_by(|a, b| a.0.cmp(&b.0)); println!("{view:?}"); // >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)] } delete_keys(&mut r, &["race:italy"]).await; let max1: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")]) .await .expect("maxlen add 1"); let max1 = max1.expect("missing stream id"); println!("{max1}"); // >>> 1-0 let max2: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")]) .await .expect("maxlen add 2"); let max2 = max2.expect("missing stream id"); println!("{max2}"); // >>> 2-0 let max3: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")]) .await .expect("maxlen add 3"); let max3 = max3.expect("missing stream id"); println!("{max3}"); // >>> 3-0 if let Ok(res) = r.xlen("race:italy").await { let res: usize = res; println!("{res}"); // >>> 2 } if let Ok(res) = r.xrange_all("race:italy").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } delete_keys(&mut r, &["race:italy"]).await; let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).await.expect("trim seed 1"); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).await.expect("trim seed 2"); if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)).await { let res: usize = res; println!("{res}"); // >>> 0 } seed_trim_stream(&mut r).await; if let Ok(res) = r .xtrim_options( "mystream", &StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10), ) .await { let res: usize = res; println!("{res}"); // >>> 0 } delete_keys(&mut r, &["race:italy"]).await; let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).await.expect("xdel seed 1"); let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).await.expect("xdel seed 2"); if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } if let Ok(res) = r.xdel("race:italy", &["3-0"]).await { let res: usize = res; println!("{res}"); // >>> 1 } if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])] } } } -
Read up to 100 new stream entries, starting at the end of the stream, and block for up to 300 ms if no entries are being written:
Use XREAD with BLOCK to wait for new entries when you need to consume messages as they arrive> XREAD COUNT 100 BLOCK 300 STREAMS race:france $ (nil)""" Code samples for Stream doc pages: https://redis.io/docs/latest/develop/data-types/streams/ """ import redis r = redis.Redis(decode_responses=True) res1 = r.xadd( "race:france", {"rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1}, ) print(res1) # >>> 1692629576966-0 res2 = r.xadd( "race:france", {"rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1}, ) print(res2) # >>> 1692629594113-0 res3 = r.xadd( "race:france", {"rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1}, ) print(res3) # >>> 1692629613374-0 res4 = r.xrange("race:france", "1691765278160-0", "+", 2) print( res4 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] res5 = r.xread(streams={"race:france": 0}, count=100, block=300) print( res5 ) # >>> [ # ['race:france', # [('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ), # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # )] # ] # ] res6 = r.xadd( "race:france", {"rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2}, ) print(res6) # >>> 1692629676124-0 res7 = r.xlen("race:france") print(res7) # >>> 4 res8 = r.xadd("race:usa", {"racer": "Castilla"}, id="0-1") print(res8) # >>> 0-1 res9 = r.xadd("race:usa", {"racer": "Norem"}, id="0-2") print(res9) # >>> 0-2 try: res10 = r.xadd("race:usa", {"racer": "Prickett"}, id="0-1") print(res10) # >>> 0-1 except redis.exceptions.ResponseError as e: print(e) # >>> WRONGID # Not yet implemented res11 = r.xrange("race:france", "-", "+") print( res11 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ), # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # ), # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res12 = r.xrange("race:france", 1692629576965, 1692629576967) print( res12 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ) # ] res13 = r.xrange("race:france", "-", "+", 2) print( res13 ) # >>> [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] res14 = r.xrange("race:france", "(1692629594113-0", "+", 2) print( res14 ) # >>> [ # ('1692629613374-0', # {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'} # ), # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res15 = r.xrange("race:france", "(1692629676124-0", "+", 2) print(res15) # >>> [] res16 = r.xrevrange("race:france", "+", "-", 1) print( res16 ) # >>> [ # ('1692629676124-0', # {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'} # ) # ] res17 = r.xread(streams={"race:france": 0}, count=2) print( res17 ) # >>> [ # ['race:france', [ # ('1692629576966-0', # {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'} # ), # ('1692629594113-0', # {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'} # ) # ] # ] # ] res18 = r.xgroup_create("race:france", "france_riders", "$") print(res18) # >>> True res19 = r.xgroup_create("race:italy", "italy_riders", "$", mkstream=True) print(res19) # >>> True r.xadd("race:italy", {"rider": "Castilla"}) r.xadd("race:italy", {"rider": "Royce"}) r.xadd("race:italy", {"rider": "Sam-Bodden"}) r.xadd("race:italy", {"rider": "Prickett"}) r.xadd("race:italy", {"rider": "Norem"}) res20 = r.xreadgroup( streams={"race:italy": ">"}, consumername="Alice", groupname="italy_riders", count=1, ) print(res20) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]] res21 = r.xreadgroup( streams={"race:italy": 0}, consumername="Alice", groupname="italy_riders", count=1, ) print(res21) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]] res22 = r.xack("race:italy", "italy_riders", "1692629925771-0") print(res22) # >>> 1 res23 = r.xreadgroup( streams={"race:italy": 0}, consumername="Alice", groupname="italy_riders", count=1, ) print(res23) # >>> [['race:italy', []]] res24 = r.xreadgroup( streams={"race:italy": ">"}, consumername="Bob", groupname="italy_riders", count=2, ) print( res24 ) # >>> [ # ['race:italy', [ # ('1692629925789-0', # {'rider': 'Royce'} # ), # ('1692629925790-0', # {'rider': 'Sam-Bodden'} # ) # ] # ] # ] res25 = r.xpending("race:italy", "italy_riders") print( res25 ) # >>> { # 'pending': 2, 'min': '1692629925789-0', 'max': '1692629925790-0', # 'consumers': [{'name': 'Bob', 'pending': 2}] # } res26 = r.xpending_range("race:italy", "italy_riders", "-", "+", 10) print( res26 ) # >>> [ # { # 'message_id': '1692629925789-0', 'consumer': 'Bob', # 'time_since_delivered': 31084, 'times_delivered': 1 # }, # { # 'message_id': '1692629925790-0', 'consumer': 'Bob', # 'time_since_delivered': 31084, 'times_delivered': 1 # } # ] res27 = r.xrange("race:italy", "1692629925789-0", "1692629925789-0") print(res27) # >>> [('1692629925789-0', {'rider': 'Royce'})] res28 = r.xclaim("race:italy", "italy_riders", "Alice", 60000, ["1692629925789-0"]) print(res28) # >>> [('1692629925789-0', {'rider': 'Royce'})] res29 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "0-0", 1) print(res29) # >>> ['1692629925790-0', [('1692629925789-0', {'rider': 'Royce'})]] res30 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "(1692629925789-0", 1) print(res30) # >>> ['0-0', [('1692629925790-0', {'rider': 'Sam-Bodden'})]] res31 = r.xinfo_stream("race:italy") print( res31 ) # >>> { # 'length': 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, # 'last-generated-id': '1692629926436-0', 'groups': 1, # 'first-entry': ('1692629925771-0', {'rider': 'Castilla'}), # 'last-entry': ('1692629926436-0', {'rider': 'Norem'}) # } res32 = r.xinfo_groups("race:italy") print( res32 ) # >>> [ # { # 'name': 'italy_riders', 'consumers': 2, 'pending': 2, # 'last-delivered-id': '1692629925790-0' # } # ] res33 = r.xinfo_consumers("race:italy", "italy_riders") print( res33 ) # >>> [ # {'name': 'Alice', 'pending': 2, 'idle': 199332}, # {'name': 'Bob', 'pending': 0, 'idle': 489170} # ] r.xadd("race:italy", {"rider": "Jones"}, maxlen=2) r.xadd("race:italy", {"rider": "Wood"}, maxlen=2) r.xadd("race:italy", {"rider": "Henshaw"}, maxlen=2) res34 = r.xlen("race:italy") print(res34) # >>> 8 res35 = r.xrange("race:italy", "-", "+") print( res35 ) # >>> [ # ('1692629925771-0', {'rider': 'Castilla'}), # ('1692629925789-0', {'rider': 'Royce'}), # ('1692629925790-0', {'rider': 'Sam-Bodden'}), # ('1692629925791-0', {'rider': 'Prickett'}), # ('1692629926436-0', {'rider': 'Norem'}), # ('1692630612602-0', {'rider': 'Jones'}), # ('1692630641947-0', {'rider': 'Wood'}), # ('1692630648281-0', {'rider': 'Henshaw'}) # ] r.xadd("race:italy", {"rider": "Smith"}, maxlen=2, approximate=False) res36 = r.xrange("race:italy", "-", "+") print( res36 ) # >>> [ # ('1692630648281-0', {'rider': 'Henshaw'}), # ('1692631018238-0', {'rider': 'Smith'}) # ] res37 = r.xtrim("race:italy", maxlen=10, approximate=False) print(res37) # >>> 0 res38 = r.xtrim("race:italy", maxlen=10) print(res38) # >>> 0 res39 = r.xrange("race:italy", "-", "+") print( res39 ) # >>> [ # ('1692630648281-0', {'rider': 'Henshaw'}), # ('1692631018238-0', {'rider': 'Smith'}) # ] res40 = r.xdel("race:italy", "1692631018238-0") print(res40) # >>> 1 res41 = r.xrange("race:italy", "-", "+") print(res41) # >>> [('1692630648281-0', {'rider': 'Henshaw'})]import assert from 'assert'; import { createClient } from 'redis'; const client = await createClient(); await client.connect(); const res1 = await client.xAdd( 'race:france', '*', { 'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1' } ); console.log(res1); // >>> 1700073067968-0 N.B. actual values will differ from these examples const res2 = await client.xAdd( 'race:france', '*', { 'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1' }, ); console.log(res2); // >>> 1692629594113-0 const res3 = await client.xAdd( 'race:france', '*', { 'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1' }, ); console.log(res3); // >>> 1692629613374-0 const res4 = await client.xRange('race:france', '1691765278160-0', '+', {COUNT: 2}); console.log(res4); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] const res5 = await client.xRead({ key: 'race:france', id: '0-0' }, { COUNT: 100, BLOCK: 300 }); console.log(res5); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }] }] const res6 = await client.xAdd( 'race:france', '*', { 'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2' } ); console.log(res6); // >>> 1692629676124-0 const res7 = await client.xLen('race:france'); console.log(res7); // >>> 4 const res8 = await client.xAdd('race:usa', '0-1', { 'racer': 'Castilla' }); console.log(res8); // >>> 0-1 const res9 = await client.xAdd('race:usa', '0-2', { 'racer': 'Norem' }); console.log(res9); // >>> 0-2 try { const res10 = await client.xAdd('race:usa', '0-1', { 'racer': 'Prickett' }); console.log(res10); // >>> 0-1 } catch (error) { console.error(error); // >>> [SimpleError: ERR The ID specified in XADD is equal or smaller than the target stream top item] } const res11a = await client.xAdd('race:usa', '0-*', { racer: 'Norem' }); console.log(res11a); // >>> 0-3 const res11 = await client.xRange('race:france', '-', '+'); console.log(res11); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res12 = await client.xRange('race:france', '1692629576965', '1692629576967'); console.log(res12); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }] const res13 = await client.xRange('race:france', '-', '+', {COUNT: 2}); console.log(res13); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] const res14 = await client.xRange('race:france', '(1692629594113-0', '+', {COUNT: 2}); console.log(res14); // >>> [{ id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res15 = await client.xRange('race:france', '(1692629676124-0', '+', {COUNT: 2}); console.log(res15); // >>> [] const res16 = await client.xRevRange('race:france', '+', '-', {COUNT: 1}); console.log( res16 ); // >>> [{ id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }] const res17 = await client.xRead({ key: 'race:france', id: '0-0' }, { COUNT: 2 }); console.log(res17); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] }] const res18 = await client.xGroupCreate('race:france', 'france_riders', '$'); console.log(res18); // >>> OK const res19 = await client.xGroupCreate('race:italy', 'italy_riders', '$', { MKSTREAM: true }); console.log(res19); // >>> OK await client.xAdd('race:italy', '*', { 'rider': 'Castilla' }); await client.xAdd('race:italy', '*', { 'rider': 'Royce' }); await client.xAdd('race:italy', '*', { 'rider': 'Sam-Bodden' }); await client.xAdd('race:italy', '*', { 'rider': 'Prickett' }); await client.xAdd('race:italy', '*', { 'rider': 'Norem' }); const res20 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '>' }, { COUNT: 1 } ); console.log(res20); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }] const res21 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '0' }, { COUNT: 1 } ); console.log(res21); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }] const res22 = await client.xAck('race:italy', 'italy_riders', '1692629925771-0') console.log(res22); // >>> 1 const res23 = await client.xReadGroup( 'italy_riders', 'Alice', { key: 'race:italy', id: '0' }, { COUNT: 1 } ); console.log(res23); // >>> [{ name: 'race:italy', messages: [] }] const res24 = await client.xReadGroup( 'italy_riders', 'Bob', { key: 'race:italy', id: '>' }, { COUNT: 2 } ); console.log(res24); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }] }] const res25 = await client.xPending('race:italy', 'italy_riders'); console.log(res25); // >>> {'pending': 2, 'firstId': '1692629925789-0', 'lastId': '1692629925790-0', 'consumers': [{'name': 'Bob', 'deliveriesCounter': 2}]} const res26 = await client.xPendingRange('race:italy', 'italy_riders', '-', '+', 10); console.log(res26); // >>> [{'id': '1692629925789-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter:': 1}, {'id': '1692629925790-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter': 1}] const res27 = await client.xRange('race:italy', '1692629925789-0', '1692629925789-0'); console.log(res27); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }] const res28 = await client.xClaim( 'race:italy', 'italy_riders', 'Alice', 60000, ['1692629925789-0'] ); console.log(res28); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }] const res29 = await client.xAutoClaim('race:italy', 'italy_riders', 'Alice', 1, '0-0', { COUNT: 1 }); console.log(res29); // >>> { nextId: '1692629925790-0', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }], deletedMessages: [] } const res30 = await client.xAutoClaim( 'race:italy', 'italy_riders', 'Alice', 1, '(1692629925789-0', { COUNT: 1 } ); console.log(res30); // >>> { nextId: '0-0', messages: [{ id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }], deletedMessages: [] } const res31 = await client.xInfoStream('race:italy'); console.log(res31); // >>> { length: 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, 'last-generated-id': '1692629926436-0', 'max-deleted-entry-id': '0-0', 'entries-added': 5, 'recorded-first-entry-id': '1692629925771-0', groups: 1, 'first-entry': { id: '1692629925771-0', message: { rider: 'Castilla' } }, 'last-entry': { id: '1692629926436-0', message: { rider: 'Norem' } } } const res32 = await client.xInfoGroups('race:italy'); console.log(res32); // >>> [{ name: 'italy_riders', consumers: 2, pending: 3, 'last-delivered-id': '1692629925790-0', 'entries-read': 3, lag: 2 }] const res33 = await client.xInfoConsumers('race:italy', 'italy_riders'); console.log(res33); // >>> [{ name: 'Alice', pending: 3, idle: 170582, inactive: 170582 }, { name: 'Bob', pending: 0, idle: 489404, inactive: 489404 }] await client.xAdd('race:italy', '*', { 'rider': 'Jones' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); await client.xAdd('race:italy', '*', { 'rider': 'Wood' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); await client.xAdd('race:italy', '*', { 'rider': 'Henshaw' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: 2 } }); const res34 = await client.xLen('race:italy'); console.log(res34); // >>> 8 const res35 = await client.xRange('race:italy', '-', '+'); console.log(res35); // >>> [{ id: '1692629925771-0', message: { rider: 'Castilla' } }, { id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }, { id: '1692629925791-0', message: { rider: 'Prickett' } }, { id: '1692629926436-0', message: { rider: 'Norem' } }, { id: '1692630612602-0', message: { rider: 'Jones' } }, { id: '1692630641947-0', message: { rider: 'Wood' } }, { id: '1692630648281-0', message: { rider: 'Henshaw' } }] await client.xAdd('race:italy', '*', { 'rider': 'Smith' }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '=', threshold: 2 } }); const res36 = await client.xRange('race:italy', '-', '+'); console.log(res36); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }] const res37 = await client.xTrim('race:italy', 'MAXLEN', 10, { strategyModifier: '=', }); console.log(res37); // >>> 0 const res38 = await client.xTrim('race:italy', "MAXLEN", 10); console.log(res38); // >>> 0 const res39 = await client.xRange('race:italy', '-', '+'); console.log(res39); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }] const res40 = await client.xDel('race:italy', '1692631018238-0'); console.log(res40); // >>> 1 const res41 = await client.xRange('race:italy', '-', '+'); console.log(res41); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }]package io.redis.examples; import redis.clients.jedis.StreamEntryID; import redis.clients.jedis.RedisClient; public class StreamsExample { public void run() { RedisClient jedis = RedisClient.create("redis://localhost:6379"); StreamEntryID res1 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","30.2");put("position","1");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res1); // >>> 1701760582225-0 StreamEntryID res2 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Norem");put("speed","28.8");put("position","3");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res2); // >>> 1701760582225-1 StreamEntryID res3 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Prickett");put("speed","29.7");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res3); // >>> 1701760582226-0 List<StreamEntry> res4 = jedis.xrange("race:france","1701760582225-0","+",2); System.out.println(res4); // >>> [1701760841292-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701760841292-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<Map.Entry<String, List<StreamEntry>>> res5= jedis.xread(XReadParams.xReadParams().block(300).count(100),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}}); System.out.println( res5 ); // >>> [race:france=[1701761996660-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701761996661-0 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701761996661-1 {rider=Prickett, speed=29.7, location_id=1, position=2}]] StreamEntryID res6 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","29.9");put("position","2");put("location_id","1");}} , XAddParams.xAddParams()); System.out.println(res6); // >>> 1701762285679-0 long res7 = jedis.xlen("race:france"); System.out.println(res7); // >>> 4 StreamEntryID res8 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Castilla");}},XAddParams.xAddParams().id("0-1")); System.out.println(res8); // >>> 0-1 StreamEntryID res9 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-2")); System.out.println(res9); // >>> 0-2 try { StreamEntryID res10 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Prickett");}},XAddParams.xAddParams().id("0-1")); System.out.println(res10); // >>> 0-1 } catch (JedisDataException e){ System.out.println(e); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } StreamEntryID res11 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-*")); System.out.println(res11); List<StreamEntry> res12 = jedis.xrange("race:france","-","+"); System.out.println( res12 ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<StreamEntry> res13 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000),String.valueOf(System.currentTimeMillis()+1000)); System.out.println( res13 ); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<StreamEntry> res14 = jedis.xrange("race:france","-","+",2); System.out.println(res14); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<StreamEntry> res15 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000)+"-0","+",2); System.out.println(res15); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}] List<StreamEntry> res16 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()+1000)+"-0","+",2); System.out.println(res16); // >>> [] List<StreamEntry> res17 = jedis.xrevrange("race:france","+","-",1); System.out.println(res17); // >>> [1701765218592-0 {rider=Castilla, speed=29.9, location_id=1, position=2}] List<Map.Entry<String, List<StreamEntry>>> res18= jedis.xread(XReadParams.xReadParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}}); System.out.println( res18 ); // >>> [race:france=[1701765384638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701765384638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]] String res19 = jedis.xgroupCreate("race:france","france_riders",StreamEntryID.LAST_ENTRY,false); System.out.println(res19); // >>> OK String res20 = jedis.xgroupCreate("race:italy","italy_riders",StreamEntryID.LAST_ENTRY,true); System.out.println(res20); // >>> OK StreamEntryID id1 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Castilaa");}},XAddParams.xAddParams()); StreamEntryID id2 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Royce");}},XAddParams.xAddParams()); StreamEntryID id3 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Sam-Bodden");}},XAddParams.xAddParams()); StreamEntryID id4 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Prickett");}},XAddParams.xAddParams()); StreamEntryID id5 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Norem");}},XAddParams.xAddParams()); List<Map.Entry<String, List<StreamEntry>>> res21 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); System.out.println(res21); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] List<Map.Entry<String, List<StreamEntry>>> res22 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}}); System.out.println(res22); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]] long res23 = jedis.xack("race:italy","italy_riders",id1); System.out.println(res23); // >>> 1 List<Map.Entry<String, List<StreamEntry>>> res24 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}}); System.out.println(res24); // >>> [race:italy=[]] List<Map.Entry<String, List<StreamEntry>>> res25 = jedis.xreadGroup("italy_riders","Bob", XReadGroupParams.xReadGroupParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}}); System.out.println(res25); // >>> [race:italy=[1701767632261-1 {rider=Royce}, 1701767632262-0 {rider=Sam-Bodden}]] StreamPendingSummary res26 = jedis.xpending("race:italy","italy_riders"); System.out.println(res26.getConsumerMessageCount()); // >>> {Bob=2} List<StreamPendingEntry> res27 = jedis.xpending("race:italy","italy_riders",XPendingParams.xPendingParams().start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(10)); System.out.println(res27); // >>> [1701768567412-1 Bob idle:0 times:1, 1701768567412-2 Bob idle:0 times:1] List<StreamEntry> res28 = jedis.xrange("race:italy",id2.toString(),id2.toString()); System.out.println(res28); // >>> [1701768744819-1 {rider=Royce}] List<StreamEntry> res29 = jedis.xclaim("race:italy","italy_riders","Alice", 0L, XClaimParams.xClaimParams().time(60000),id2); System.out.println(res29); // >>> [1701769004195-1 {rider=Royce}] Map.Entry<StreamEntryID, List<StreamEntry>> res30 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID("0-0"),XAutoClaimParams.xAutoClaimParams().count(1)); System.out.println(res30); // >>> [1701769266831-2=[1701769266831-1 {rider=Royce}] Map.Entry<StreamEntryID, List<StreamEntry>> res31 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID(id2.toString()),XAutoClaimParams.xAutoClaimParams().count(1)); System.out.println(res31); // >>> [0-0=[1701769605847-2 {rider=Sam-Bodden}] StreamInfo res32 = jedis.xinfoStream("race:italy"); System.out.println( res32.getStreamInfo() ); // >>> {radix-tree-keys=1, radix-tree-nodes=2, entries-added=5, length=5, groups=1, max-deleted-entry-id=0-0, first-entry=1701769637612-0 {rider=Castilaa}, last-generated-id=1701769637612-4, last-entry=1701769637612-4 {rider=Norem}, recorded-first-entry-id=1701769637612-0} List<StreamGroupInfo> res33 = jedis.xinfoGroups("race:italy"); for (StreamGroupInfo a : res33){ System.out.println( a.getGroupInfo() ); // >>> {last-delivered-id=1701770253659-0, lag=2, pending=2, name=italy_riders, consumers=2, entries-read=3} } List<StreamConsumersInfo> res34 = jedis.xinfoConsumers("race:italy","italy_riders"); for (StreamConsumerInfo a : res34){ System.out.println( a.getConsumerInfo() ); // {inactive=1, idle=1, pending=1, name=Alice} , {inactive=3, idle=3, pending=1, name=Bob} } jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Jones");}},XAddParams.xAddParams().maxLen(10)); jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Wood");}},XAddParams.xAddParams().maxLen(10)); jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Henshaw");}},XAddParams.xAddParams().maxLen(10)); long res35 = jedis.xlen("race:italy"); System.out.println(res35); // >>> 8 List<StreamEntry> res36 = jedis.xrange("race:italy","-","+"); System.out.println(res36); // >>> [1701771219852-0 {rider=Castilaa}, 1701771219852-1 {rider=Royce}, 1701771219853-0 {rider=Sam-Bodden}, 1701771219853-1 {rider=Prickett}, 1701771219853-2 {rider=Norem}, 1701771219858-0 {rider=Jones}, 1701771219858-1 {rider=Wood}, 1701771219859-0 {rider=Henshaw}] StreamEntryID id6 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Smith");}},XAddParams.xAddParams().maxLen(2)); List<StreamEntry> res37 = jedis.xrange("race:italy","-","+"); System.out.println(res37); // >>> [1701771067332-1 {rider=Henshaw}, 1701771067332-2 {rider=Smith}] long res38 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10).exactTrimming()); System.out.println(res38); /// >>> 0 long res39 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10)); System.out.println(res39); /// >>> 0 List<StreamEntry> res40 = jedis.xrange("race:italy","-","+"); System.out.println(res40); // >>> [1701771356428-2 {rider=Henshaw}, 1701771356429-0 {rider=Smith}] long res41 = jedis.xdel("race:italy",id6); System.out.println(res41); // >>> 1 List<StreamEntry> res42 = jedis.xrange("race:italy","-","+"); System.out.println(res42); // >>> [1701771517639-1 {rider=Henshaw}] jedis.close(); } }package example_commands_test import ( "context" "fmt" "github.com/redis/go-redis/v9" ) func ExampleClient_xadd() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res1, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.Println(res1) // >>> 1692632086370-0 res2, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.PrintLn(res2) // >>> 1692632094485-0 res3, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, }).Result() if err != nil { panic(err) } // fmt.Println(res3) // >>> 1692632102976-0 xlen, err := rdb.XLen(ctx, "race:france").Result() if err != nil { panic(err) } fmt.Println(xlen) // >>> 3 } func ExampleClient_racefrance1() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, ID: "1692632094485-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, ID: "1692632102976-0", }).Result() if err != nil { panic(err) } res4, err := rdb.XRangeN(ctx, "race:france", "1691765278160-0", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res4) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla... res5, err := rdb.XRead(ctx, &redis.XReadArgs{ Streams: []string{"race:france", "0"}, Count: 100, Block: 300, }).Result() if err != nil { panic(err) } fmt.Println(res5) // >>> // [{race:france [{1692632086370-0 map[location_id:1 position:1... res6, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2, }, }).Result() if err != nil { panic(err) } //fmt.Println(res6) // >>> 1692632147973-0 res7, err := rdb.XLen(ctx, "race:france").Result() if err != nil { panic(err) } fmt.Println(res7) // >>> 4 } func ExampleClient_raceusa() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res8, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Castilla", }, ID: "0-1", }).Result() if err != nil { panic(err) } fmt.Println(res8) // >>> 0-1 res9, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Norem", }, ID: "0-2", }).Result() if err != nil { panic(err) } fmt.Println(res9) // >>> 0-2 res10, err := rdb.XAdd(ctx, &redis.XAddArgs{ Values: map[string]interface{}{ "racer": "Prickett", }, ID: "0-1", }).Result() if err != nil { // fmt.Println(err) // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } res11, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:usa", Values: map[string]interface{}{ "racer": "Prickett", }, ID: "0-*", }).Result() if err != nil { panic(err) } fmt.Println(res11) // >>> 0-3 } func ExampleClient_racefrance2() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1, }, ID: "1692632094485-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1, }, ID: "1692632102976-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2, }, ID: "1692632147973-0", }).Result() if err != nil { panic(err) } res12, err := rdb.XRange(ctx, "race:france", "-", "+").Result() if err != nil { panic(err) } fmt.Println(res12) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla... res13, err := rdb.XRange(ctx, "race:france", "1692632086369", "1692632086371", ).Result() if err != nil { panic(err) } fmt.Println(res13) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0}] res14, err := rdb.XRangeN(ctx, "race:france", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res14) // >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}] res15, err := rdb.XRangeN(ctx, "race:france", "(1692632094485-0", "+", 2, ).Result() if err != nil { panic(err) } fmt.Println(res15) // >>> [{1692632102976-0 map[location_id:1 position:2 rider:Prickett speed:29.7] 0 0} {1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}] res16, err := rdb.XRangeN(ctx, "race:france", "(1692632147973-0", "+", 2, ).Result() if err != nil { panic(err) } fmt.Println(res16) // >>> [] res17, err := rdb.XRevRangeN(ctx, "race:france", "+", "-", 1).Result() if err != nil { panic(err) } fmt.Println(res17) // >>> [{1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}] res18, err := rdb.XRead(ctx, &redis.XReadArgs{ Streams: []string{"race:france", "0"}, Count: 2, }).Result() if err != nil { panic(err) } fmt.Println(res18) // >>> [{race:france [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}]}] } func ExampleClient_xgroupcreate() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:france", Values: map[string]interface{}{ "rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1, }, ID: "1692632086370-0", }).Result() if err != nil { panic(err) } res19, err := rdb.XGroupCreate(ctx, "race:france", "france_riders", "$").Result() if err != nil { panic(err) } fmt.Println(res19) // >>> OK } func ExampleClient_xgroupcreatemkstream() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) res20, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } fmt.Println(res20) // >>> OK } func ExampleClient_xgroupread() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Castilla"}, }).Result() // >>> 1692632639151-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Royce"}, }).Result() // >>> 1692632647899-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Sam-Bodden"}, }).Result() // >>> 1692632662819-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Prickett"}, }).Result() // >>> 1692632670501-0 if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Norem"}, }).Result() // >>> 1692632678249-0 if err != nil { panic(err) } // fmt.Println(res25) res21, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Alice", Count: 1, }).Result() if err != nil { panic(err) } // fmt.Println(res21) // >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}] xlen, err := rdb.XLen(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(xlen) } func ExampleClient_raceitaly() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XGroupCreateMkStream(ctx, "race:italy", "italy_riders", "$", ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Castilla"}, ID: "1692632639151-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Royce"}, ID: "1692632647899-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Sam-Bodden"}, ID: "1692632662819-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Prickett"}, ID: "1692632670501-0", }).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", Values: map[string]interface{}{"rider": "Norem"}, ID: "1692632678249-0", }).Result() if err != nil { panic(err) } _, err = rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Alice", Count: 1, }).Result() if err != nil { panic(err) } res22, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", "0"}, Group: "italy_riders", Consumer: "Alice", }).Result() if err != nil { panic(err) } fmt.Println(res22) // >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}] res23, err := rdb.XAck(ctx, "race:italy", "italy_riders", "1692632639151-0", ).Result() if err != nil { panic(err) } fmt.Println(res23) // >>> 1 res24, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", "0"}, Group: "italy_riders", Consumer: "Alice", }).Result() if err != nil { panic(err) } fmt.Println(res24) // >>> [{race:italy []}] res25, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{ Streams: []string{"race:italy", ">"}, Group: "italy_riders", Consumer: "Bob", Count: 2, }).Result() if err != nil { panic(err) } fmt.Println(res25) // >>> [{race:italy [{1692632647899-0 map[rider:Royce] 0 0} {1692632662819-0 map[rider:Sam-Bodden] 0 0}]}] res26, err := rdb.XPending(ctx, "race:italy", "italy_riders").Result() if err != nil { panic(err) } fmt.Println(res26) // >>> &{2 1692632647899-0 1692632662819-0 map[Bob:2]} res27, err := rdb.XPendingExt(ctx, &redis.XPendingExtArgs{ Stream: "race:italy", Group: "italy_riders", Start: "-", End: "+", Count: 10, }).Result() if err != nil { panic(err) } // fmt.Println(res27) // >>> [{1692632647899-0 Bob 0s 1} {1692632662819-0 Bob 0s 1}] res28, err := rdb.XRange(ctx, "race:italy", "1692632647899-0", "1692632647899-0", ).Result() if err != nil { panic(err) } fmt.Println(res28) // >>> [{1692632647899-0 map[rider:Royce] 0 0}] res29, err := rdb.XClaim(ctx, &redis.XClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Alice", MinIdle: 0, Messages: []string{"1692632647899-0"}, }).Result() if err != nil { panic(err) } fmt.Println(res29) res30, res30a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Alice", Start: "0-0", Count: 1, }).Result() if err != nil { panic(err) } fmt.Println(res30) // >>> [{1692632647899-0 map[rider:Royce] 0 0}] fmt.Println(res30a) // >>> 1692632662819-0 res31, res31a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{ Stream: "race:italy", Group: "italy_riders", Consumer: "Lora", Start: "(1692632662819-0", Count: 1, }).Result() if err != nil { panic(err) } fmt.Println(res31) // >>> [] fmt.Println(res31a) // >>> 0-0 res32, err := rdb.XInfoStream(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res32.Length) // >>> 5 fmt.Println(res32.FirstEntry) // >>> {1692632639151-0 map[rider:Castilla] 0 0} res33, err := rdb.XInfoGroups(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res33) // >>> [{italy_riders 3 2 1692632662819-0 3 2}] res34, err := rdb.XInfoConsumers(ctx, "race:italy", "italy_riders").Result() if err != nil { panic(err) } // fmt.Println(res34) // >>> [{Alice 1 1ms 1ms} {Bob 1 2ms 2ms} {Lora 0 1ms -1ms}] _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Jones"}, }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Wood"}, }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Henshaw"}, }, ).Result() if err != nil { panic(err) } res35, err := rdb.XLen(ctx, "race:italy").Result() if err != nil { panic(err) } fmt.Println(res35) // >>> 2 res36, err := rdb.XRange(ctx, "race:italy", "-", "+").Result() if err != nil { panic(err) } // fmt.Println(res36) // >>> [{1726649529170-1 map[rider:Wood] 0 0} {1726649529171-0 map[rider:Henshaw] 0 0}] res37, err := rdb.XTrimMaxLen(ctx, "race:italy", 10).Result() if err != nil { panic(err) } fmt.Println(res37) // >>> 0 res38, err := rdb.XTrimMaxLenApprox(ctx, "race:italy", 10, 20).Result() if err != nil { panic(err) } fmt.Println(res38) // >>> 0 } func ExampleClient_xdel() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password docs DB: 0, // use default DB }) _, err := rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Wood"}, ID: "1692633198206-0", }, ).Result() if err != nil { panic(err) } _, err = rdb.XAdd(ctx, &redis.XAddArgs{ Stream: "race:italy", MaxLen: 2, Values: map[string]interface{}{"rider": "Henshaw"}, ID: "1692633208557-0", }, ).Result() if err != nil { panic(err) } res39, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res39) // >>> [{1692633198206-0 map[rider:Wood] 0 0} {1692633208557-0 map[rider:Henshaw] 0 0}] res40, err := rdb.XDel(ctx, "race:italy", "1692633208557-0").Result() if err != nil { panic(err) } fmt.Println(res40) // 1 res41, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result() if err != nil { panic(err) } fmt.Println(res41) // >>> [{1692633198206-0 map[rider:Wood] 0 0}] }using NRedisStack.Tests; using StackExchange.Redis; public class StreamTutorial { public void Run() { var muxer = ConnectionMultiplexer.Connect("localhost:6379"); var db = muxer.GetDatabase(); RedisValue res1 = db.StreamAdd( "race:france", [ new("rider", "Castilla"), new("speed", 30.2), new("position", 1), new("location_id", 1) ] ); Console.WriteLine(res1); // >>> 1712668482289-0 RedisValue res2 = db.StreamAdd( "race:france", [ new("rider", "Norem"), new("speed", 28.8), new("position", 3), new("location_id", 1) ] ); Console.WriteLine(res2); // >>> 1712668766534-1 RedisValue res3 = db.StreamAdd( "race:france", [ new("rider", "Prickett"), new("speed", 29.7), new("position", 2), new("location_id", 1) ] ); Console.WriteLine(res3); // >>> 1712669055705-0 // Tests for 'xadd' step. StreamEntry[] res4 = db.StreamRange("race:france", "1712668482289-0", "+", 2); foreach (StreamEntry entry in res4) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xrange' step. StreamEntry[] res5 = db.StreamRead("race:france", 0, 100); foreach (StreamEntry entry in res4) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // Tests for 'xread_block' step. RedisValue res6 = db.StreamAdd( "race:france", [ new("rider", "Castilla"), new("speed", 29.9), new("position", 1), new("location_id", 2) ] ); Console.WriteLine(res6); // >>> 1712675674750-0 // Tests for 'xadd_2' step. long res7 = db.StreamLength("race:france"); Console.WriteLine(res7); // >>> 4 // Tests for 'xlen' step. RedisValue res8 = db.StreamAdd( "race:usa", [ new("racer", "Castilla") ], "0-1" ); Console.WriteLine(res8); // >>> 0-1 RedisValue res9 = db.StreamAdd( "race:usa", [ new("racer", "Norem") ], "0-2" ); Console.WriteLine(res9); // >>> 0-2 // Tests for 'xadd_id' step. try { RedisValue res10 = db.StreamAdd( "race:usa", [ new("racer", "Prickett") ], "0-1" ); } catch (RedisServerException ex) { Console.WriteLine(ex); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item } // Tests for 'xadd_bad_id' step. RedisValue res11 = ""; Version version = muxer.GetServer("localhost:6379").Version; if (version.Major >= 7) { res11 = db.StreamAdd( "race:usa", [ new("rider", "Norem") ], "0-*" ); Console.WriteLine(res11); // >>> "0-3" } // Tests for 'xadd_7' step. StreamEntry[] res12 = db.StreamRange("race:france", "-", "+"); foreach (StreamEntry entry in res12) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrange_all' step. StreamEntry[] res13 = db.StreamRange("race:france", 1712668482289, 1712668482291); foreach (StreamEntry entry in res13) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // Tests for 'xrange_time' step. StreamEntry[] res14 = db.StreamRange("race:france", "-", "+", 2); foreach (StreamEntry entry in res14) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xrange_step_1' step. StreamEntry[] res15 = db.StreamRange("race:france", "(1712668766534-1", "+", 2); foreach (StreamEntry entry in res15) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1] // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrange_step_2' step. StreamEntry[] res16 = db.StreamRange("race:france", "(1712675674750-0", "+", 2); foreach (StreamEntry entry in res16) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> <empty array> // Tests for 'xrange_empty' step. StreamEntry[] res17 = db.StreamRange("race:france", "+", "-", 1, Order.Descending); foreach (StreamEntry entry in res17) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2] // Tests for 'xrevrange' step. StreamEntry[] res18 = db.StreamRead("race:france", 0, 2); foreach (StreamEntry entry in res18) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1] // >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1] // Tests for 'xread' step. bool res19 = db.StreamCreateConsumerGroup("race:france", "france_riders", "$"); Console.WriteLine(res19); // >>> true // Tests for 'xgroup_create' step. bool res20 = db.StreamCreateConsumerGroup("race:italy", "italy_riders", "$", true); Console.WriteLine(res20); // >>> true // Tests for 'xgroup_create_mkstream' step. RedisValue groupRes = db.StreamAdd( "race:italy", [new("rider", "Castilla")] ); // 1712744323758-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Royce")] ); // 1712744358384-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Sam-Bodden")] ); // 1712744379676-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Prickett")] ); // 1712744399401-0 groupRes = db.StreamAdd( "race:italy", [new("rider", "Norem")] ); // 1712744413117-0 StreamEntry[] res21 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", ">", 1); foreach (StreamEntry entry in res21) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744323758-0: [rider: Castilla] // Tests for 'xgroup_read' step. StreamEntry[] res22 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0"); foreach (StreamEntry entry in res22) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); // >>> 1712744323758-0: [rider: Castilla] } // Tests for 'xgroup_read_id' step. long res23 = db.StreamAcknowledge("race:italy", "italy_riders", "1712744323758-0"); Console.WriteLine(res23); // >>> 1 StreamEntry[] res24 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0"); foreach (StreamEntry entry in res24) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> <empty array> // Tests for 'xack' step. StreamEntry[] res25 = db.StreamReadGroup("race:italy", "italy_riders", "Bob", ">", 2); foreach (StreamEntry entry in res25) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // >>> 1712744379676-0: [rider: Sam-Bodden] // Tests for 'xgroup_read_bob' step. StreamPendingInfo res26 = db.StreamPending("race:italy", "italy_riders"); Console.WriteLine($"pending: {res26.PendingMessageCount}, min: {res26.LowestPendingMessageId}, max: {res26.HighestPendingMessageId}, consumers:[{string.Join(", ", res26.Consumers.Select(c => $"{c.Name}: {c.PendingMessageCount}"))}]"); // >>> pending: 2, min: 1712747506906-0, max: 1712747506907-0, consumers:[name: Bob, pending:2] // Tests for 'xpending' step. StreamPendingMessageInfo[] res27 = db.StreamPendingMessages( "race:italy", "italy_riders", 10, "", "-", "+" ); foreach (StreamPendingMessageInfo info in res27) { Console.WriteLine($"message_id: {info.MessageId}, consumer: {info.ConsumerName}, time_since_delivered: {info.IdleTimeInMilliseconds}, times_delivered: {info.DeliveryCount}"); } // >>> message_id: min: 1712747506906-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1 // >>> message_id: min: 1712747506907-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1 // Tests for 'xpending_plus_minus' step. StreamEntry[] res28 = db.StreamRange("race:italy", "1712744358384-0", "1712744358384-0"); foreach (StreamEntry entry in res28) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // Tests for 'xrange_pending' step. StreamEntry[] res29 = db.StreamClaim( "race:italy", "italy_riders", "Alice", 60000, [1712744358384 - 0] ); foreach (StreamEntry entry in res29) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712744358384-0: [rider: Royce] // Tests for 'xclaim' step. StreamAutoClaimResult res30 = db.StreamAutoClaim( "race:italy", "italy_riders", "Alice", 1, "0-0", 1 ); Console.WriteLine($"{res30.NextStartId}, ({string.Join(", ", res30.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})"); // >>> 1712744379676-0, (1712744358384-0: [rider: Royce]) // Tests for 'xautoclaim' step. StreamAutoClaimResult res31 = db.StreamAutoClaim( "race:italy", "italy_riders", "Alice", 1, "(1712744358384-0", 1 ); Console.WriteLine($"{res31.NextStartId}, ({string.Join(", ", res31.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})"); // >>> 0-0, (1712744379676-0: [rider: Sam-Bodden]) // Tests for 'xautoclaim_cursor' step. StreamInfo res32 = db.StreamInfo("race:italy"); Console.WriteLine($"length: {res32.Length}, radix-tree-keys: {res32.RadixTreeKeys}, radix-tree-nodes: {res32.RadixTreeNodes}, last-generated-id: {res32.LastGeneratedId}, first-entry: {$"{res32.FirstEntry.Id}: [{string.Join(", ", res32.FirstEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}, last-entry: {$"{res32.LastEntry.Id}: [{string.Join(", ", res32.LastEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}"); // >>> length: 5, radix-tree-keys: 1, radix-tree-nodes: 2, last-generated-id: 1712756762686-1, first-entry: 1712756762685-0: [rider: Castilla], last-entry: 1712756762686-1: [rider: Norem] // Tests for 'xinfo' step. StreamGroupInfo[] res33 = db.StreamGroupInfo("race:italy"); foreach (StreamGroupInfo info in res33) { Console.WriteLine($"name: {info.Name}, consumers: {info.ConsumerCount}, pending: {info.PendingMessageCount}, last-delivered-id: {info.LastDeliveredId}"); } // >>> name: italy_riders, consumers: 2, pending: 2, last-delivered-id: 1712757192730-2 // Tests for 'xinfo_groups' step. StreamConsumerInfo[] res34 = db.StreamConsumerInfo("race:italy", "italy_riders"); foreach (StreamConsumerInfo info in res34) { Console.WriteLine($"name: {info.Name}, pending: {info.PendingMessageCount}, idle: {info.IdleTimeInMilliseconds}"); } // >>> name: Alice, pending: 1, idle: 7717 // >>> name: Bob, pending: 0, idle: 7722 // Tests for 'xinfo_consumers' step. db.StreamAdd( "race:italy", [new("rider", "Jones")], null, 2, true ); db.StreamAdd( "race:italy", [new("rider", "Wood")], null, 2, true ); db.StreamAdd( "race:italy", [new("rider", "Henshaw")], null, 2, true ); long res35 = db.StreamLength("race:italy"); Console.WriteLine(res35); // >>> 8 StreamEntry[] res36 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res36) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712758336128-0: [rider: Castilla] // >>> 1712758336128-1: [rider: Royce] // >>> 1712758336128-2: [rider: Sam-Bodden] // >>> 1712758336129-0: [rider: Prickett] // >>> 1712758336139-0: [rider: Norem] // >>> 1712758340854-0: [rider: Jones] // >>> 1712758341645-0: [rider: Wood] // >>> 1712758342134-0: [rider: Henshaw] db.StreamAdd( "race:italy", [new("rider", "Smith")], null, 2, false ); StreamEntry[] res37 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res37) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // 1712758746476-1: [rider: Henshaw] // 1712758746477-0: [rider: Smith] // Tests for 'maxlen' step. long res38 = db.StreamTrim("race:italy", 10, false); Console.WriteLine(res38); // >>> 0 // Tests for 'xtrim' step. long res39 = db.StreamTrim("race:italy", 10, true); Console.WriteLine(res39); // >>> 0 // Tests for 'xtrim2' step. StreamEntry[] res40 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res40) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712759694003-0: [rider: Henshaw] // >>> 1712759694003-1: [rider: Smith] long res41 = db.StreamDelete("race:italy", ["1712759694003-1"]); Console.WriteLine(res41); // >>> 1 StreamEntry[] res42 = db.StreamRange("race:italy", "-", "+"); foreach (StreamEntry entry in res42) { Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"); } // >>> 1712759694003-0: [rider: Henshaw] // Tests for 'xdel' step. } }require 'redis' r = Redis.new res1 = r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => 30.2, 'position' => 1, 'location_id' => 1 }) puts res1 # 1692632086370-0, for example res2 = r.xadd('race:france', { 'rider' => 'Norem', 'speed' => 28.8, 'position' => 3, 'location_id' => 1 }) puts res2 # 1692632094485-0, for example res3 = r.xadd('race:france', { 'rider' => 'Prickett', 'speed' => 29.7, 'position' => 2, 'location_id' => 1 }) puts res3 # 1692632102976-0, for example r.del('race:france') r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1' }, id: '1692632086370-0') r.xadd('race:france', { 'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1' }, id: '1692632094485-0') r.xadd('race:france', { 'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1' }, id: '1692632102976-0') r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2' }, id: '1692632147973-0') res4 = r.xrange('race:france', '1692632086370-0', '+', count: 2) puts res4.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') res5 = r.xread(['race:france'], ['$'], count: 100, block: 300) puts res5.inspect # {} res6 = r.xadd('race:france', { 'rider' => 'Castilla', 'speed' => 29.9, 'position' => 1, 'location_id' => 2 }) puts res6 # 1692632147973-0, for example r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632147973-0') res7 = r.xlen('race:france') puts res7 # 4 r.del('race:usa') res8 = r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1') puts res8 # 0-1 res9 = r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2') puts res9 # 0-2 begin r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-1') rescue Redis::CommandError => e puts e.message # ERR The ID specified in XADD is equal or smaller than the target stream top item end r.del('race:usa') r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1') r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2') res10 = r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-*') puts res10 # 0-3 r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res11 = r.xrange('race:france', '-', '+') puts res11.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}], # ["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}], # ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') res12 = r.xrange('race:france', '1692632086369', '1692632086371') puts res12.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res13 = r.xrange('race:france', '-', '+', count: 2) puts res13.inspect # [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]] r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0') r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0') r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0') r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0') res14 = r.xrange('race:france', '(1692632094485-0', '+', count: 2) puts res14.inspect # [["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}], # ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] res15 = r.xrange('race:france', '(1692632147973-0', '+', count: 2) puts res15.inspect # [] res16 = r.xrevrange('race:france', '+', '-', count: 1) puts res16.inspect # [["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]] res17 = r.xread(['race:france'], ['0'], count: 2) puts res17.inspect # {"race:france"=>[["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}], # ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]]} r.del('race:france') r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0') res18 = r.xgroup(:create, 'race:france', 'france_riders', '$') puts res18 # OK r.del('race:italy') res19 = r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true) puts res19 # OK r.del('race:italy') r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true) r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0') r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0') r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0') r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0') r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0') res20 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['>'], count: 1) puts res20.inspect # {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]} res21 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0'], count: 1) puts res21.inspect # {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]} res22 = r.xack('race:italy', 'italy_riders', '1692632639151-0') puts res22 # 1 res23 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0']) puts res23.inspect # {"race:italy"=>[]} res24 = r.xreadgroup('italy_riders', 'Bob', ['race:italy'], ['>'], count: 2) puts res24.inspect # {"race:italy"=>[["1692632647899-0", {"rider"=>"Royce"}], # ["1692632662819-0", {"rider"=>"Sam-Bodden"}]]} res25 = r.xpending('race:italy', 'italy_riders') puts res25.inspect # {"size"=>2, "min_entry_id"=>"1692632647899-0", "max_entry_id"=>"1692632662819-0", "consumers"=>{"Bob"=>"2"}} res26 = r.xpending('race:italy', 'italy_riders', '-', '+', 10) puts res26.inspect res27 = r.xrange('race:italy', '1692632647899-0', '1692632647899-0') puts res27.inspect # [["1692632647899-0", {"rider"=>"Royce"}]] res28 = r.xclaim('race:italy', 'italy_riders', 'Alice', 0, '1692632647899-0') puts res28.inspect # [["1692632647899-0", {"rider"=>"Royce"}]] res29 = r.xautoclaim('race:italy', 'italy_riders', 'Alice', 0, '0-0', count: 1) puts res29.inspect # {"next"=>"1692632662819-0", "entries"=>[["1692632647899-0", {"rider"=>"Royce"}]]} res30 = r.xautoclaim('race:italy', 'italy_riders', 'Lora', 0, res29['next'], count: 1) puts res30.inspect # {"next"=>"0-0", "entries"=>[["1692632662819-0", {"rider"=>"Sam-Bodden"}]]} res31 = r.xinfo(:stream, 'race:italy') puts res31.inspect res32 = r.xinfo(:groups, 'race:italy') puts res32.inspect res33 = r.xinfo(:consumers, 'race:italy', 'italy_riders') puts res33.inspect r.del('race:italy') r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0') r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0') r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0') r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0') r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0') r.xadd('race:italy', {'rider' => 'Jones'}, id: '1692633189161-0', maxlen: 2) r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0', maxlen: 2) r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0', maxlen: 2) res34 = r.xlen('race:italy') puts res34 # 2 res35 = r.xrange('race:italy', '-', '+') puts res35.inspect # [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]] res36 = r.xtrim('race:italy', 10, approximate: false) puts res36 # 0 r.del('mystream') 1.upto(10) do |n| r.xadd('mystream', {'field' => 'value'}, id: "#{n}-0") end res37 = r.xtrim('mystream', 10, approximate: true) puts res37 # 0 r.del('race:italy') r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0') r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0') res38 = r.xrange('race:italy', '-', '+', count: 2) puts res38.inspect # [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]] res39 = r.xdel('race:italy', '1692633208557-0') puts res39 # 1 res40 = r.xrange('race:italy', '-', '+', count: 2) puts res40.inspect # [["1692633198206-0", {"rider"=>"Wood"}]]mod stream_tests { use redis::{ streams::{ StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply, StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply, StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode, StreamTrimOptions, }, Commands, }; use std::{thread::sleep, time::Duration}; fn delete_keys(r: &mut redis::Connection, keys: &[&str]) { let _: usize = r.del(keys).unwrap_or(0); } fn add_france_fixed(r: &mut redis::Connection) { delete_keys(r, &["race:france"]); let _: Option<String> = r .xadd( "race:france", "1692632086370-0", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .expect("add france 1"); let _: Option<String> = r .xadd( "race:france", "1692632094485-0", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .expect("add france 2"); let _: Option<String> = r .xadd( "race:france", "1692632102976-0", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .expect("add france 3"); let _: Option<String> = r .xadd( "race:france", "1692632147973-0", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .expect("add france 4"); } fn seed_usa_fixed(r: &mut redis::Connection) { delete_keys(r, &["race:usa"]); let _: Option<String> = r .xadd("race:usa", "0-1", &[("racer", "Castilla")]) .expect("add usa 1"); let _: Option<String> = r .xadd("race:usa", "0-2", &[("racer", "Norem")]) .expect("add usa 2"); } fn seed_italy_group_base(r: &mut redis::Connection) { delete_keys(r, &["race:italy"]); let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .expect("create italy group"); let _: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .expect("add italy 1"); let _: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .expect("add italy 2"); let _: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .expect("add italy 3"); let _: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .expect("add italy 4"); let _: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .expect("add italy 5"); } fn seed_italy_alice_pending(r: &mut redis::Connection) { seed_italy_group_base(r); let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .expect("alice read pending"); } fn seed_italy_after_ack(r: &mut redis::Connection) { seed_italy_alice_pending(r); let _: usize = r .xack("race:italy", "italy_riders", &["1692632639151-0"]) .expect("ack first italy message"); } fn seed_italy_bob_pending(r: &mut redis::Connection) { seed_italy_after_ack(r); let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .expect("bob read pending"); } fn seed_italy_info_state(r: &mut redis::Connection) { seed_italy_bob_pending(r); sleep(Duration::from_millis(5)); let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .expect("alice claim"); sleep(Duration::from_millis(5)); let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"]) .expect("lora claim"); } fn seed_trim_stream(r: &mut redis::Connection) { delete_keys(r, &["mystream"]); for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] { let _: Option<String> = r .xadd("mystream", id, &[("field", "value")]) .expect("seed mystream"); } } fn run() { let mut r = match redis::Client::open("redis://127.0.0.1") { Ok(client) => match client.get_connection() { Ok(conn) => conn, Err(e) => { println!("Failed to connect to Redis: {e}"); return; } }, Err(e) => { println!("Failed to create Redis client: {e}"); return; } }; let res1 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .expect("xadd 1"); res.expect("missing stream id") }; println!("{res1}"); // >>> 1692632086370-0 let res2 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .expect("xadd 2"); res.expect("missing stream id") }; println!("{res2}"); // >>> 1692632094485-0 let res3 = { let res: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .expect("xadd 3"); res.expect("missing stream id") }; println!("{res3}"); // >>> 1692632102976-0 add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r); let opts = StreamReadOptions::default().count(100).block(300); if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts) { let res: Option<StreamReadReply> = res; println!("{res:?}"); // >>> None } if let Ok(res) = r.xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 1692632147973-0 } add_france_fixed(&mut r); if let Ok(res) = r.xlen("race:france") { let res: usize = res; println!("{res}"); // >>> 4 } delete_keys(&mut r, &["race:usa"]); if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-1 } if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-2 } let res: redis::RedisResult<Option<String>> = r.xadd("race:usa", "0-1", &[("racer", "Prickett")]); match res { Ok(_) => {} Err(e) => { let msg = e.to_string(); println!("{msg}"); // >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item } } seed_usa_fixed(&mut r); if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]) { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-3 } add_france_fixed(&mut r); if let Ok(res) = r.xrange_all("race:france") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [] } add_france_fixed(&mut r); if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r); let opts = StreamReadOptions::default().count(2); if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let reply = res.expect("xread should return data"); let view: Vec<_> = reply .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])] } add_france_fixed(&mut r); if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$") { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]); if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$") { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]); let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .expect("create italy group"); let italy_1: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .expect("italy1"); let italy_1 = italy_1.expect("missing stream id"); println!("{italy_1}"); // >>> 1692632639151-0 let italy_2: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .expect("italy2"); let italy_2 = italy_2.expect("missing stream id"); println!("{italy_2}"); // >>> 1692632647899-0 let italy_3: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .expect("italy3"); let italy_3 = italy_3.expect("missing stream id"); println!("{italy_3}"); // >>> 1692632662819-0 let italy_4: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .expect("italy4"); let italy_4 = italy_4.expect("missing stream id"); println!("{italy_4}"); // >>> 1692632670501-0 let italy_5: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .expect("italy5"); let italy_5 = italy_5.expect("missing stream id"); println!("{italy_5}"); // >>> 1692632678249-0 let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup read should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r); let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r); if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]) { let res: usize = res; println!("{res}"); // >>> 1 } let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [])] } seed_italy_after_ack(&mut r); let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("bob should receive data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])] } seed_italy_bob_pending(&mut r); if let Ok(res) = r.xpending("race:italy", "italy_riders") { let res: StreamPendingReply = res; let view = match res { StreamPendingReply::Empty => None, StreamPendingReply::Data(data) => Some(( data.count, data.start_id.clone(), data.end_id.clone(), data.consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending)) .collect::<Vec<_>>(), )), } .expect("pending summary"); println!("{view:?}"); // >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)]) } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10) { let res: StreamPendingCountReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), entry.consumer.clone(), entry.last_delivered_ms, entry.times_delivered, ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)] } seed_italy_bob_pending(&mut r); if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); if let Ok(res) = r.xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) { let res: redis::streams::StreamClaimReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); let opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r.xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts) { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])]) } seed_italy_bob_pending(&mut r); sleep(Duration::from_millis(5)); let first_opts = StreamAutoClaimOptions::default().count(1); let _: redis::streams::StreamAutoClaimReply = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts) .expect("first autoclaim"); let next_opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r.xautoclaim_options( "race:italy", "italy_riders", "Lora", 1, "(1692632647899-0", next_opts, ) { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])]) } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_stream("race:italy") { let res: StreamInfoStreamReply = res; let view = ( res.length, res.radix_tree_keys, res.groups, res.last_generated_id.clone(), res.first_entry.id.clone(), res.last_entry.id.clone(), ); println!("{view:?}"); // >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0") } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_groups("race:italy") { let res: StreamInfoGroupsReply = res; let view: Vec<_> = res .groups .iter() .map(|group| { ( group.name.clone(), group.consumers, group.pending, group.last_delivered_id.clone(), ) }) .collect(); println!("{view:?}"); // >>> [("italy_riders", 3, 2, "1692632662819-0")] } seed_italy_info_state(&mut r); if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders") { let res: StreamInfoConsumersReply = res; let mut view: Vec<_> = res .consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle)) .collect(); view.sort_by(|a, b| a.0.cmp(&b.0)); println!("{view:?}"); // >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)] } delete_keys(&mut r, &["race:italy"]); let max1: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")]) .expect("maxlen add 1"); let max1 = max1.expect("missing stream id"); println!("{max1}"); // >>> 1-0 let max2: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")]) .expect("maxlen add 2"); let max2 = max2.expect("missing stream id"); println!("{max2}"); // >>> 2-0 let max3: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")]) .expect("maxlen add 3"); let max3 = max3.expect("missing stream id"); println!("{max3}"); // >>> 3-0 if let Ok(res) = r.xlen("race:italy") { let res: usize = res; println!("{res}"); // >>> 2 } if let Ok(res) = r.xrange_all("race:italy") { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } delete_keys(&mut r, &["race:italy"]); let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).expect("trim seed 1"); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).expect("trim seed 2"); if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)) { let res: usize = res; println!("{res}"); // >>> 0 } seed_trim_stream(&mut r); if let Ok(res) = r.xtrim_options( "mystream", &StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10), ) { let res: usize = res; println!("{res}"); // >>> 0 } delete_keys(&mut r, &["race:italy"]); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).expect("xdel seed 1"); let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).expect("xdel seed 2"); if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } if let Ok(res) = r.xdel("race:italy", &["3-0"]) { let res: usize = res; println!("{res}"); // >>> 1 } if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])] } } }mod tests { use redis::{ streams::{ StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply, StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply, StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode, StreamTrimOptions, }, AsyncCommands, }; use tokio::time::{sleep, Duration}; async fn delete_keys(r: &mut redis::aio::MultiplexedConnection, keys: &[&str]) { let _: usize = r.del(keys).await.unwrap_or(0); } async fn add_france_fixed(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:france"]).await; let _: Option<String> = r .xadd( "race:france", "1692632086370-0", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .await .expect("add france 1"); let _: Option<String> = r .xadd( "race:france", "1692632094485-0", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .await .expect("add france 2"); let _: Option<String> = r .xadd( "race:france", "1692632102976-0", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .await .expect("add france 3"); let _: Option<String> = r .xadd( "race:france", "1692632147973-0", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .await .expect("add france 4"); } async fn seed_usa_fixed(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:usa"]).await; let _: Option<String> = r .xadd("race:usa", "0-1", &[("racer", "Castilla")]) .await .expect("add usa 1"); let _: Option<String> = r .xadd("race:usa", "0-2", &[("racer", "Norem")]) .await .expect("add usa 2"); } async fn seed_italy_group_base(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["race:italy"]).await; let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .await .expect("create italy group"); let _: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .await .expect("add italy 1"); let _: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .await .expect("add italy 2"); let _: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .await .expect("add italy 3"); let _: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .await .expect("add italy 4"); let _: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .await .expect("add italy 5"); } async fn seed_italy_alice_pending(r: &mut redis::aio::MultiplexedConnection) { seed_italy_group_base(r).await; let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .await .expect("alice read pending"); } async fn seed_italy_after_ack(r: &mut redis::aio::MultiplexedConnection) { seed_italy_alice_pending(r).await; let _: usize = r .xack("race:italy", "italy_riders", &["1692632639151-0"]) .await .expect("ack first italy message"); } async fn seed_italy_bob_pending(r: &mut redis::aio::MultiplexedConnection) { seed_italy_after_ack(r).await; let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); let _: Option<StreamReadReply> = r .xread_options(&["race:italy"], &[">"], &opts) .await .expect("bob read pending"); } async fn seed_italy_info_state(r: &mut redis::aio::MultiplexedConnection) { seed_italy_bob_pending(r).await; sleep(Duration::from_millis(5)).await; let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .await .expect("alice claim"); sleep(Duration::from_millis(5)).await; let _: redis::streams::StreamClaimReply = r .xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"]) .await .expect("lora claim"); } async fn seed_trim_stream(r: &mut redis::aio::MultiplexedConnection) { delete_keys(r, &["mystream"]).await; for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] { let _: Option<String> = r .xadd("mystream", id, &[("field", "value")]) .await .expect("seed mystream"); } } async fn run() { let mut r = match redis::Client::open("redis://127.0.0.1") { Ok(client) => match client.get_multiplexed_async_connection().await { Ok(conn) => conn, Err(e) => { println!("Failed to connect to Redis: {e}"); return; } }, Err(e) => { println!("Failed to create Redis client: {e}"); return; } }; let res1: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1"), ], ) .await .expect("xadd 1"); let res1 = res1.expect("missing stream id"); println!("{res1}"); // >>> 1692632086370-0 let res2: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1"), ], ) .await .expect("xadd 2"); let res2 = res2.expect("missing stream id"); println!("{res2}"); // >>> 1692632094485-0 let res3: Option<String> = r .xadd( "race:france", "*", &[ ("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1"), ], ) .await .expect("xadd 3"); let res3 = res3.expect("missing stream id"); println!("{res3}"); // >>> 1692632102976-0 add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r).await; let opts = StreamReadOptions::default().count(100).block(300); if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts).await { let res: Option<StreamReadReply> = res; println!("{res:?}"); // >>> None } if let Ok(res) = r .xadd( "race:france", "*", &[ ("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2"), ], ) .await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 1692632147973-0 } add_france_fixed(&mut r).await; if let Ok(res) = r.xlen("race:france").await { let res: usize = res; println!("{res}"); // >>> 4 } delete_keys(&mut r, &["race:usa"]).await; if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-1 } if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-2 } let res: redis::RedisResult<Option<String>> = r.xadd("race:usa", "0-1", &[("racer", "Prickett")]).await; match res { Ok(_) => {} Err(e) => { let msg = e.to_string(); println!("{msg}"); // >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item } } seed_usa_fixed(&mut r).await; if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]).await { let res: Option<String> = res; let res = res.expect("missing stream id"); println!("{res}"); // >>> 0-3 } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_all("race:france").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [] } add_france_fixed(&mut r).await; if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect(); println!("{view:?}"); // >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])] } add_france_fixed(&mut r).await; let opts = StreamReadOptions::default().count(2); if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xread should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![ ("rider".to_string(), entry.get::<String>("rider").expect("missing rider")), ("speed".to_string(), entry.get::<String>("speed").expect("missing speed")), ("position".to_string(), entry.get::<String>("position").expect("missing position")), ( "location_id".to_string(), entry.get::<String>("location_id").expect("missing location_id"), ), ], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])] } add_france_fixed(&mut r).await; if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$").await { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]).await; if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$").await { let res: () = res; let _ = res; println!("OK"); // >>> OK } delete_keys(&mut r, &["race:italy"]).await; let _: () = r .xgroup_create_mkstream("race:italy", "italy_riders", "$") .await .expect("create italy group"); let italy_1: Option<String> = r .xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")]) .await .expect("italy1"); let italy_1 = italy_1.expect("missing stream id"); println!("{italy_1}"); // >>> 1692632639151-0 let italy_2: Option<String> = r .xadd("race:italy", "1692632647899-0", &[("rider", "Royce")]) .await .expect("italy2"); let italy_2 = italy_2.expect("missing stream id"); println!("{italy_2}"); // >>> 1692632647899-0 let italy_3: Option<String> = r .xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")]) .await .expect("italy3"); let italy_3 = italy_3.expect("missing stream id"); println!("{italy_3}"); // >>> 1692632662819-0 let italy_4: Option<String> = r .xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")]) .await .expect("italy4"); let italy_4 = italy_4.expect("missing stream id"); println!("{italy_4}"); // >>> 1692632670501-0 let italy_5: Option<String> = r .xadd("race:italy", "1692632678249-0", &[("rider", "Norem")]) .await .expect("italy5"); let italy_5 = italy_5.expect("missing stream id"); println!("{italy_5}"); // >>> 1692632678249-0 let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup read should return data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r).await; let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])] } seed_italy_alice_pending(&mut r).await; if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]).await { let res: usize = res; println!("{res}"); // >>> 1 } let opts = StreamReadOptions::default().group("italy_riders", "Alice"); if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("xgroup history") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [])] } seed_italy_after_ack(&mut r).await; let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2); if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await { let res: Option<StreamReadReply> = res; let view: Vec<_> = res .expect("bob should receive data") .keys .iter() .map(|stream| { ( stream.key.clone(), stream .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect::<Vec<_>>(), ) }) .collect(); println!("{view:?}"); // >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])] } seed_italy_bob_pending(&mut r).await; if let Ok(res) = r.xpending("race:italy", "italy_riders").await { let res: StreamPendingReply = res; let view = match res { StreamPendingReply::Empty => None, StreamPendingReply::Data(data) => Some(( data.count, data.start_id.clone(), data.end_id.clone(), data.consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending)) .collect::<Vec<_>>(), )), } .expect("pending summary"); println!("{view:?}"); // >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)]) } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10).await { let res: StreamPendingCountReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), entry.consumer.clone(), entry.last_delivered_ms, entry.times_delivered, ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)] } seed_italy_bob_pending(&mut r).await; if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; if let Ok(res) = r .xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) .await { let res: redis::streams::StreamClaimReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])] } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; let opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts) .await { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])]) } seed_italy_bob_pending(&mut r).await; sleep(Duration::from_millis(5)).await; let first_opts = StreamAutoClaimOptions::default().count(1); let _: redis::streams::StreamAutoClaimReply = r .xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts) .await .expect("first autoclaim"); let next_opts = StreamAutoClaimOptions::default().count(1); if let Ok(res) = r .xautoclaim_options( "race:italy", "italy_riders", "Lora", 1, "(1692632647899-0", next_opts, ) .await { let res: redis::streams::StreamAutoClaimReply = res; let claimed: Vec<_> = res .claimed .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{:?}", (res.next_stream_id.clone(), &claimed)); // >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])]) } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_stream("race:italy").await { let res: StreamInfoStreamReply = res; let view = ( res.length, res.radix_tree_keys, res.groups, res.last_generated_id.clone(), res.first_entry.id.clone(), res.last_entry.id.clone(), ); println!("{view:?}"); // >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0") } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_groups("race:italy").await { let res: StreamInfoGroupsReply = res; let view: Vec<_> = res .groups .iter() .map(|group| { ( group.name.clone(), group.consumers, group.pending, group.last_delivered_id.clone(), ) }) .collect(); println!("{view:?}"); // >>> [("italy_riders", 3, 2, "1692632662819-0")] } seed_italy_info_state(&mut r).await; if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders").await { let res: StreamInfoConsumersReply = res; let mut view: Vec<_> = res .consumers .iter() .map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle)) .collect(); view.sort_by(|a, b| a.0.cmp(&b.0)); println!("{view:?}"); // >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)] } delete_keys(&mut r, &["race:italy"]).await; let max1: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")]) .await .expect("maxlen add 1"); let max1 = max1.expect("missing stream id"); println!("{max1}"); // >>> 1-0 let max2: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")]) .await .expect("maxlen add 2"); let max2 = max2.expect("missing stream id"); println!("{max2}"); // >>> 2-0 let max3: Option<String> = r .xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")]) .await .expect("maxlen add 3"); let max3 = max3.expect("missing stream id"); println!("{max3}"); // >>> 3-0 if let Ok(res) = r.xlen("race:italy").await { let res: usize = res; println!("{res}"); // >>> 2 } if let Ok(res) = r.xrange_all("race:italy").await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } delete_keys(&mut r, &["race:italy"]).await; let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).await.expect("trim seed 1"); let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).await.expect("trim seed 2"); if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)).await { let res: usize = res; println!("{res}"); // >>> 0 } seed_trim_stream(&mut r).await; if let Ok(res) = r .xtrim_options( "mystream", &StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10), ) .await { let res: usize = res; println!("{res}"); // >>> 0 } delete_keys(&mut r, &["race:italy"]).await; let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).await.expect("xdel seed 1"); let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).await.expect("xdel seed 2"); if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])] } if let Ok(res) = r.xdel("race:italy", &["3-0"]).await { let res: usize = res; println!("{res}"); // >>> 1 } if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await { let res: StreamRangeReply = res; let view: Vec<_> = res .ids .iter() .map(|entry| { ( entry.id.clone(), vec![( "rider".to_string(), entry.get::<String>("rider").expect("missing rider"), )], ) }) .collect(); println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])] } } }
Performance
Adding an entry to a stream is O(1). Accessing any single entry is O(n), where n is the length of the ID. Since stream IDs are typically short and of a fixed length, this effectively reduces to a constant time lookup. For details on why, note that streams are implemented as radix trees.
Simply put, Redis streams provide highly efficient inserts and reads. See each command's time complexity for the details.
Streams basics
Streams are an append-only data structure. The fundamental write command, called XADD, appends a new entry to the specified stream.
Each stream entry consists of one or more field-value pairs, somewhat like a dictionary or a Redis hash:
> XADD race:france * rider Castilla speed 29.9 position 1 location_id 2
"1692632147973-0""""
Code samples for Stream doc pages:
https://redis.io/docs/latest/develop/data-types/streams/
"""
import redis
r = redis.Redis(decode_responses=True)
res1 = r.xadd(
"race:france",
{"rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1},
)
print(res1) # >>> 1692629576966-0
res2 = r.xadd(
"race:france",
{"rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1},
)
print(res2) # >>> 1692629594113-0
res3 = r.xadd(
"race:france",
{"rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1},
)
print(res3) # >>> 1692629613374-0
res4 = r.xrange("race:france", "1691765278160-0", "+", 2)
print(
res4
) # >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# )
# ]
res5 = r.xread(streams={"race:france": 0}, count=100, block=300)
print(
res5
)
# >>> [
# ['race:france',
# [('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# ),
# ('1692629613374-0',
# {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}
# )]
# ]
# ]
res6 = r.xadd(
"race:france",
{"rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2},
)
print(res6) # >>> 1692629676124-0
res7 = r.xlen("race:france")
print(res7) # >>> 4
res8 = r.xadd("race:usa", {"racer": "Castilla"}, id="0-1")
print(res8) # >>> 0-1
res9 = r.xadd("race:usa", {"racer": "Norem"}, id="0-2")
print(res9) # >>> 0-2
try:
res10 = r.xadd("race:usa", {"racer": "Prickett"}, id="0-1")
print(res10) # >>> 0-1
except redis.exceptions.ResponseError as e:
print(e) # >>> WRONGID
# Not yet implemented
res11 = r.xrange("race:france", "-", "+")
print(
res11
)
# >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# ),
# ('1692629613374-0',
# {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}
# ),
# ('1692629676124-0',
# {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'}
# )
# ]
res12 = r.xrange("race:france", 1692629576965, 1692629576967)
print(
res12
)
# >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# )
# ]
res13 = r.xrange("race:france", "-", "+", 2)
print(
res13
)
# >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# )
# ]
res14 = r.xrange("race:france", "(1692629594113-0", "+", 2)
print(
res14
)
# >>> [
# ('1692629613374-0',
# {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}
# ),
# ('1692629676124-0',
# {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'}
# )
# ]
res15 = r.xrange("race:france", "(1692629676124-0", "+", 2)
print(res15) # >>> []
res16 = r.xrevrange("race:france", "+", "-", 1)
print(
res16
)
# >>> [
# ('1692629676124-0',
# {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'}
# )
# ]
res17 = r.xread(streams={"race:france": 0}, count=2)
print(
res17
)
# >>> [
# ['race:france', [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# )
# ]
# ]
# ]
res18 = r.xgroup_create("race:france", "france_riders", "$")
print(res18) # >>> True
res19 = r.xgroup_create("race:italy", "italy_riders", "$", mkstream=True)
print(res19) # >>> True
r.xadd("race:italy", {"rider": "Castilla"})
r.xadd("race:italy", {"rider": "Royce"})
r.xadd("race:italy", {"rider": "Sam-Bodden"})
r.xadd("race:italy", {"rider": "Prickett"})
r.xadd("race:italy", {"rider": "Norem"})
res20 = r.xreadgroup(
streams={"race:italy": ">"},
consumername="Alice",
groupname="italy_riders",
count=1,
)
print(res20) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]]
res21 = r.xreadgroup(
streams={"race:italy": 0},
consumername="Alice",
groupname="italy_riders",
count=1,
)
print(res21) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]]
res22 = r.xack("race:italy", "italy_riders", "1692629925771-0")
print(res22) # >>> 1
res23 = r.xreadgroup(
streams={"race:italy": 0},
consumername="Alice",
groupname="italy_riders",
count=1,
)
print(res23) # >>> [['race:italy', []]]
res24 = r.xreadgroup(
streams={"race:italy": ">"},
consumername="Bob",
groupname="italy_riders",
count=2,
)
print(
res24
)
# >>> [
# ['race:italy', [
# ('1692629925789-0',
# {'rider': 'Royce'}
# ),
# ('1692629925790-0',
# {'rider': 'Sam-Bodden'}
# )
# ]
# ]
# ]
res25 = r.xpending("race:italy", "italy_riders")
print(
res25
)
# >>> {
# 'pending': 2, 'min': '1692629925789-0', 'max': '1692629925790-0',
# 'consumers': [{'name': 'Bob', 'pending': 2}]
# }
res26 = r.xpending_range("race:italy", "italy_riders", "-", "+", 10)
print(
res26
)
# >>> [
# {
# 'message_id': '1692629925789-0', 'consumer': 'Bob',
# 'time_since_delivered': 31084, 'times_delivered': 1
# },
# {
# 'message_id': '1692629925790-0', 'consumer': 'Bob',
# 'time_since_delivered': 31084, 'times_delivered': 1
# }
# ]
res27 = r.xrange("race:italy", "1692629925789-0", "1692629925789-0")
print(res27) # >>> [('1692629925789-0', {'rider': 'Royce'})]
res28 = r.xclaim("race:italy", "italy_riders", "Alice", 60000, ["1692629925789-0"])
print(res28) # >>> [('1692629925789-0', {'rider': 'Royce'})]
res29 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "0-0", 1)
print(res29) # >>> ['1692629925790-0', [('1692629925789-0', {'rider': 'Royce'})]]
res30 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "(1692629925789-0", 1)
print(res30) # >>> ['0-0', [('1692629925790-0', {'rider': 'Sam-Bodden'})]]
res31 = r.xinfo_stream("race:italy")
print(
res31
)
# >>> {
# 'length': 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2,
# 'last-generated-id': '1692629926436-0', 'groups': 1,
# 'first-entry': ('1692629925771-0', {'rider': 'Castilla'}),
# 'last-entry': ('1692629926436-0', {'rider': 'Norem'})
# }
res32 = r.xinfo_groups("race:italy")
print(
res32
)
# >>> [
# {
# 'name': 'italy_riders', 'consumers': 2, 'pending': 2,
# 'last-delivered-id': '1692629925790-0'
# }
# ]
res33 = r.xinfo_consumers("race:italy", "italy_riders")
print(
res33
)
# >>> [
# {'name': 'Alice', 'pending': 2, 'idle': 199332},
# {'name': 'Bob', 'pending': 0, 'idle': 489170}
# ]
r.xadd("race:italy", {"rider": "Jones"}, maxlen=2)
r.xadd("race:italy", {"rider": "Wood"}, maxlen=2)
r.xadd("race:italy", {"rider": "Henshaw"}, maxlen=2)
res34 = r.xlen("race:italy")
print(res34) # >>> 8
res35 = r.xrange("race:italy", "-", "+")
print(
res35
)
# >>> [
# ('1692629925771-0', {'rider': 'Castilla'}),
# ('1692629925789-0', {'rider': 'Royce'}),
# ('1692629925790-0', {'rider': 'Sam-Bodden'}),
# ('1692629925791-0', {'rider': 'Prickett'}),
# ('1692629926436-0', {'rider': 'Norem'}),
# ('1692630612602-0', {'rider': 'Jones'}),
# ('1692630641947-0', {'rider': 'Wood'}),
# ('1692630648281-0', {'rider': 'Henshaw'})
# ]
r.xadd("race:italy", {"rider": "Smith"}, maxlen=2, approximate=False)
res36 = r.xrange("race:italy", "-", "+")
print(
res36
)
# >>> [
# ('1692630648281-0', {'rider': 'Henshaw'}),
# ('1692631018238-0', {'rider': 'Smith'})
# ]
res37 = r.xtrim("race:italy", maxlen=10, approximate=False)
print(res37) # >>> 0
res38 = r.xtrim("race:italy", maxlen=10)
print(res38) # >>> 0
res39 = r.xrange("race:italy", "-", "+")
print(
res39
)
# >>> [
# ('1692630648281-0', {'rider': 'Henshaw'}),
# ('1692631018238-0', {'rider': 'Smith'})
# ]
res40 = r.xdel("race:italy", "1692631018238-0")
print(res40) # >>> 1
res41 = r.xrange("race:italy", "-", "+")
print(res41) # >>> [('1692630648281-0', {'rider': 'Henshaw'})]
import assert from 'assert';
import {
createClient
} from 'redis';
const client = await createClient();
await client.connect();
const res1 = await client.xAdd(
'race:france', '*', {
'rider': 'Castilla',
'speed': '30.2',
'position': '1',
'location_id': '1'
}
);
console.log(res1); // >>> 1700073067968-0 N.B. actual values will differ from these examples
const res2 = await client.xAdd(
'race:france', '*', {
'rider': 'Norem',
'speed': '28.8',
'position': '3',
'location_id': '1'
},
);
console.log(res2); // >>> 1692629594113-0
const res3 = await client.xAdd(
'race:france', '*', {
'rider': 'Prickett',
'speed': '29.7',
'position': '2',
'location_id': '1'
},
);
console.log(res3); // >>> 1692629613374-0
const res4 = await client.xRange('race:france', '1691765278160-0', '+', {COUNT: 2});
console.log(res4); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }]
const res5 = await client.xRead({
key: 'race:france',
id: '0-0'
}, {
COUNT: 100,
BLOCK: 300
});
console.log(res5); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }] }]
const res6 = await client.xAdd(
'race:france', '*', {
'rider': 'Castilla',
'speed': '29.9',
'position': '1',
'location_id': '2'
}
);
console.log(res6); // >>> 1692629676124-0
const res7 = await client.xLen('race:france');
console.log(res7); // >>> 4
const res8 = await client.xAdd('race:usa', '0-1', {
'racer': 'Castilla'
});
console.log(res8); // >>> 0-1
const res9 = await client.xAdd('race:usa', '0-2', {
'racer': 'Norem'
});
console.log(res9); // >>> 0-2
try {
const res10 = await client.xAdd('race:usa', '0-1', {
'racer': 'Prickett'
});
console.log(res10); // >>> 0-1
} catch (error) {
console.error(error); // >>> [SimpleError: ERR The ID specified in XADD is equal or smaller than the target stream top item]
}
const res11a = await client.xAdd('race:usa', '0-*', { racer: 'Norem' });
console.log(res11a); // >>> 0-3
const res11 = await client.xRange('race:france', '-', '+');
console.log(res11); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }]
const res12 = await client.xRange('race:france', '1692629576965', '1692629576967');
console.log(res12); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }]
const res13 = await client.xRange('race:france', '-', '+', {COUNT: 2});
console.log(res13); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }]
const res14 = await client.xRange('race:france', '(1692629594113-0', '+', {COUNT: 2});
console.log(res14); // >>> [{ id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }]
const res15 = await client.xRange('race:france', '(1692629676124-0', '+', {COUNT: 2});
console.log(res15); // >>> []
const res16 = await client.xRevRange('race:france', '+', '-', {COUNT: 1});
console.log(
res16
); // >>> [{ id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }]
const res17 = await client.xRead({
key: 'race:france',
id: '0-0'
}, {
COUNT: 2
});
console.log(res17); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] }]
const res18 = await client.xGroupCreate('race:france', 'france_riders', '$');
console.log(res18); // >>> OK
const res19 = await client.xGroupCreate('race:italy', 'italy_riders', '$', {
MKSTREAM: true
});
console.log(res19); // >>> OK
await client.xAdd('race:italy', '*', {
'rider': 'Castilla'
});
await client.xAdd('race:italy', '*', {
'rider': 'Royce'
});
await client.xAdd('race:italy', '*', {
'rider': 'Sam-Bodden'
});
await client.xAdd('race:italy', '*', {
'rider': 'Prickett'
});
await client.xAdd('race:italy', '*', {
'rider': 'Norem'
});
const res20 = await client.xReadGroup(
'italy_riders',
'Alice', {
key: 'race:italy',
id: '>'
}, {
COUNT: 1
}
);
console.log(res20); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }]
const res21 = await client.xReadGroup(
'italy_riders',
'Alice', {
key: 'race:italy',
id: '0'
}, {
COUNT: 1
}
);
console.log(res21); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }]
const res22 = await client.xAck('race:italy', 'italy_riders', '1692629925771-0')
console.log(res22); // >>> 1
const res23 = await client.xReadGroup(
'italy_riders',
'Alice', {
key: 'race:italy',
id: '0'
}, {
COUNT: 1
}
);
console.log(res23); // >>> [{ name: 'race:italy', messages: [] }]
const res24 = await client.xReadGroup(
'italy_riders',
'Bob', {
key: 'race:italy',
id: '>'
}, {
COUNT: 2
}
);
console.log(res24); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }] }]
const res25 = await client.xPending('race:italy', 'italy_riders');
console.log(res25); // >>> {'pending': 2, 'firstId': '1692629925789-0', 'lastId': '1692629925790-0', 'consumers': [{'name': 'Bob', 'deliveriesCounter': 2}]}
const res26 = await client.xPendingRange('race:italy', 'italy_riders', '-', '+', 10);
console.log(res26); // >>> [{'id': '1692629925789-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter:': 1}, {'id': '1692629925790-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter': 1}]
const res27 = await client.xRange('race:italy', '1692629925789-0', '1692629925789-0');
console.log(res27); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }]
const res28 = await client.xClaim(
'race:italy', 'italy_riders', 'Alice', 60000, ['1692629925789-0']
);
console.log(res28); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }]
const res29 = await client.xAutoClaim('race:italy', 'italy_riders', 'Alice', 1, '0-0', {
COUNT: 1
});
console.log(res29); // >>> { nextId: '1692629925790-0', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }], deletedMessages: [] }
const res30 = await client.xAutoClaim(
'race:italy', 'italy_riders', 'Alice', 1, '(1692629925789-0',
{
COUNT: 1
}
);
console.log(res30); // >>> { nextId: '0-0', messages: [{ id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }], deletedMessages: [] }
const res31 = await client.xInfoStream('race:italy');
console.log(res31); // >>> { length: 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, 'last-generated-id': '1692629926436-0', 'max-deleted-entry-id': '0-0', 'entries-added': 5, 'recorded-first-entry-id': '1692629925771-0', groups: 1, 'first-entry': { id: '1692629925771-0', message: { rider: 'Castilla' } }, 'last-entry': { id: '1692629926436-0', message: { rider: 'Norem' } } }
const res32 = await client.xInfoGroups('race:italy');
console.log(res32); // >>> [{ name: 'italy_riders', consumers: 2, pending: 3, 'last-delivered-id': '1692629925790-0', 'entries-read': 3, lag: 2 }]
const res33 = await client.xInfoConsumers('race:italy', 'italy_riders');
console.log(res33); // >>> [{ name: 'Alice', pending: 3, idle: 170582, inactive: 170582 }, { name: 'Bob', pending: 0, idle: 489404, inactive: 489404 }]
await client.xAdd('race:italy', '*', {
'rider': 'Jones'
}, {
TRIM: {
strategy: 'MAXLEN',
strategyModifier: '~',
threshold: 2
}
});
await client.xAdd('race:italy', '*', {
'rider': 'Wood'
}, {
TRIM: {
strategy: 'MAXLEN',
strategyModifier: '~',
threshold: 2
}
});
await client.xAdd('race:italy', '*', {
'rider': 'Henshaw'
}, {
TRIM: {
strategy: 'MAXLEN',
strategyModifier: '~',
threshold: 2
}
});
const res34 = await client.xLen('race:italy');
console.log(res34); // >>> 8
const res35 = await client.xRange('race:italy', '-', '+');
console.log(res35); // >>> [{ id: '1692629925771-0', message: { rider: 'Castilla' } }, { id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }, { id: '1692629925791-0', message: { rider: 'Prickett' } }, { id: '1692629926436-0', message: { rider: 'Norem' } }, { id: '1692630612602-0', message: { rider: 'Jones' } }, { id: '1692630641947-0', message: { rider: 'Wood' } }, { id: '1692630648281-0', message: { rider: 'Henshaw' } }]
await client.xAdd('race:italy', '*', {
'rider': 'Smith'
}, {
TRIM: {
strategy: 'MAXLEN',
strategyModifier: '=',
threshold: 2
}
});
const res36 = await client.xRange('race:italy', '-', '+');
console.log(res36); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }]
const res37 = await client.xTrim('race:italy', 'MAXLEN', 10, {
strategyModifier: '=',
});
console.log(res37); // >>> 0
const res38 = await client.xTrim('race:italy', "MAXLEN", 10);
console.log(res38); // >>> 0
const res39 = await client.xRange('race:italy', '-', '+');
console.log(res39); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }, { id: '1692631018238-0', message: { rider: 'Smith' } }]
const res40 = await client.xDel('race:italy', '1692631018238-0');
console.log(res40); // >>> 1
const res41 = await client.xRange('race:italy', '-', '+');
console.log(res41); // >>> [{ id: '1692630648281-0', message: { rider: 'Henshaw' } }]
package io.redis.examples;
import redis.clients.jedis.StreamEntryID;
import redis.clients.jedis.RedisClient;
public class StreamsExample {
public void run() {
RedisClient jedis = RedisClient.create("redis://localhost:6379");
StreamEntryID res1 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","30.2");put("position","1");put("location_id","1");}} , XAddParams.xAddParams());
System.out.println(res1); // >>> 1701760582225-0
StreamEntryID res2 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Norem");put("speed","28.8");put("position","3");put("location_id","1");}} , XAddParams.xAddParams());
System.out.println(res2); // >>> 1701760582225-1
StreamEntryID res3 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Prickett");put("speed","29.7");put("position","2");put("location_id","1");}} , XAddParams.xAddParams());
System.out.println(res3); // >>> 1701760582226-0
List<StreamEntry> res4 = jedis.xrange("race:france","1701760582225-0","+",2);
System.out.println(res4); // >>> [1701760841292-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701760841292-1 {rider=Norem, speed=28.8, location_id=1, position=3}]
List<Map.Entry<String, List<StreamEntry>>> res5= jedis.xread(XReadParams.xReadParams().block(300).count(100),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}});
System.out.println(
res5
); // >>> [race:france=[1701761996660-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701761996661-0 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701761996661-1 {rider=Prickett, speed=29.7, location_id=1, position=2}]]
StreamEntryID res6 = jedis.xadd("race:france",new HashMap<String,String>(){{put("rider","Castilla");put("speed","29.9");put("position","2");put("location_id","1");}} , XAddParams.xAddParams());
System.out.println(res6); // >>> 1701762285679-0
long res7 = jedis.xlen("race:france");
System.out.println(res7); // >>> 4
StreamEntryID res8 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Castilla");}},XAddParams.xAddParams().id("0-1"));
System.out.println(res8); // >>> 0-1
StreamEntryID res9 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-2"));
System.out.println(res9); // >>> 0-2
try {
StreamEntryID res10 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Prickett");}},XAddParams.xAddParams().id("0-1"));
System.out.println(res10); // >>> 0-1
}
catch (JedisDataException e){
System.out.println(e); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item
}
StreamEntryID res11 = jedis.xadd("race:usa", new HashMap<String,String>(){{put("racer","Norem");}},XAddParams.xAddParams().id("0-*"));
System.out.println(res11);
List<StreamEntry> res12 = jedis.xrange("race:france","-","+");
System.out.println(
res12
); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}]
List<StreamEntry> res13 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000),String.valueOf(System.currentTimeMillis()+1000));
System.out.println(
res13
); // >>> [1701764734160-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764734160-1 {rider=Norem, speed=28.8, location_id=1, position=3}, 1701764734161-0 {rider=Prickett, speed=29.7, location_id=1, position=2}, 1701764734162-0 {rider=Castilla, speed=29.9, location_id=1, position=2}]
List<StreamEntry> res14 = jedis.xrange("race:france","-","+",2);
System.out.println(res14); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]
List<StreamEntry> res15 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()-1000)+"-0","+",2);
System.out.println(res15); // >>> [1701764887638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701764887638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]
List<StreamEntry> res16 = jedis.xrange("race:france",String.valueOf(System.currentTimeMillis()+1000)+"-0","+",2);
System.out.println(res16); // >>> []
List<StreamEntry> res17 = jedis.xrevrange("race:france","+","-",1);
System.out.println(res17); // >>> [1701765218592-0 {rider=Castilla, speed=29.9, location_id=1, position=2}]
List<Map.Entry<String, List<StreamEntry>>> res18= jedis.xread(XReadParams.xReadParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:france",new StreamEntryID());}});
System.out.println(
res18
); // >>> [race:france=[1701765384638-0 {rider=Castilla, speed=30.2, location_id=1, position=1}, 1701765384638-1 {rider=Norem, speed=28.8, location_id=1, position=3}]]
String res19 = jedis.xgroupCreate("race:france","france_riders",StreamEntryID.LAST_ENTRY,false);
System.out.println(res19); // >>> OK
String res20 = jedis.xgroupCreate("race:italy","italy_riders",StreamEntryID.LAST_ENTRY,true);
System.out.println(res20); // >>> OK
StreamEntryID id1 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Castilaa");}},XAddParams.xAddParams());
StreamEntryID id2 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Royce");}},XAddParams.xAddParams());
StreamEntryID id3 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Sam-Bodden");}},XAddParams.xAddParams());
StreamEntryID id4 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Prickett");}},XAddParams.xAddParams());
StreamEntryID id5 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Norem");}},XAddParams.xAddParams());
List<Map.Entry<String, List<StreamEntry>>> res21 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}});
System.out.println(res21); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]]
List<Map.Entry<String, List<StreamEntry>>> res22 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}});
System.out.println(res22); // >>> [race:italy=[1701766299006-0 {rider=Castilaa}]]
long res23 = jedis.xack("race:italy","italy_riders",id1);
System.out.println(res23); // >>> 1
List<Map.Entry<String, List<StreamEntry>>> res24 = jedis.xreadGroup("italy_riders","Alice", XReadGroupParams.xReadGroupParams().count(1),new HashMap<String,StreamEntryID>(){{put("race:italy",new StreamEntryID());}});
System.out.println(res24); // >>> [race:italy=[]]
List<Map.Entry<String, List<StreamEntry>>> res25 = jedis.xreadGroup("italy_riders","Bob", XReadGroupParams.xReadGroupParams().count(2),new HashMap<String,StreamEntryID>(){{put("race:italy",StreamEntryID.UNRECEIVED_ENTRY);}});
System.out.println(res25); // >>> [race:italy=[1701767632261-1 {rider=Royce}, 1701767632262-0 {rider=Sam-Bodden}]]
StreamPendingSummary res26 = jedis.xpending("race:italy","italy_riders");
System.out.println(res26.getConsumerMessageCount()); // >>> {Bob=2}
List<StreamPendingEntry> res27 = jedis.xpending("race:italy","italy_riders",XPendingParams.xPendingParams().start(StreamEntryID.MINIMUM_ID).end(StreamEntryID.MAXIMUM_ID).count(10));
System.out.println(res27); // >>> [1701768567412-1 Bob idle:0 times:1, 1701768567412-2 Bob idle:0 times:1]
List<StreamEntry> res28 = jedis.xrange("race:italy",id2.toString(),id2.toString());
System.out.println(res28); // >>> [1701768744819-1 {rider=Royce}]
List<StreamEntry> res29 = jedis.xclaim("race:italy","italy_riders","Alice", 0L, XClaimParams.xClaimParams().time(60000),id2);
System.out.println(res29); // >>> [1701769004195-1 {rider=Royce}]
Map.Entry<StreamEntryID, List<StreamEntry>> res30 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID("0-0"),XAutoClaimParams.xAutoClaimParams().count(1));
System.out.println(res30); // >>> [1701769266831-2=[1701769266831-1 {rider=Royce}]
Map.Entry<StreamEntryID, List<StreamEntry>> res31 = jedis.xautoclaim("race:italy","italy_riders","Alice",1L,new StreamEntryID(id2.toString()),XAutoClaimParams.xAutoClaimParams().count(1));
System.out.println(res31); // >>> [0-0=[1701769605847-2 {rider=Sam-Bodden}]
StreamInfo res32 = jedis.xinfoStream("race:italy");
System.out.println(
res32.getStreamInfo()
); // >>> {radix-tree-keys=1, radix-tree-nodes=2, entries-added=5, length=5, groups=1, max-deleted-entry-id=0-0, first-entry=1701769637612-0 {rider=Castilaa}, last-generated-id=1701769637612-4, last-entry=1701769637612-4 {rider=Norem}, recorded-first-entry-id=1701769637612-0}
List<StreamGroupInfo> res33 = jedis.xinfoGroups("race:italy");
for (StreamGroupInfo a : res33){
System.out.println(
a.getGroupInfo()
); // >>> {last-delivered-id=1701770253659-0, lag=2, pending=2, name=italy_riders, consumers=2, entries-read=3}
}
List<StreamConsumersInfo> res34 = jedis.xinfoConsumers("race:italy","italy_riders");
for (StreamConsumerInfo a : res34){
System.out.println(
a.getConsumerInfo()
); // {inactive=1, idle=1, pending=1, name=Alice} , {inactive=3, idle=3, pending=1, name=Bob}
}
jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Jones");}},XAddParams.xAddParams().maxLen(10));
jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Wood");}},XAddParams.xAddParams().maxLen(10));
jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Henshaw");}},XAddParams.xAddParams().maxLen(10));
long res35 = jedis.xlen("race:italy");
System.out.println(res35); // >>> 8
List<StreamEntry> res36 = jedis.xrange("race:italy","-","+");
System.out.println(res36); // >>> [1701771219852-0 {rider=Castilaa}, 1701771219852-1 {rider=Royce}, 1701771219853-0 {rider=Sam-Bodden}, 1701771219853-1 {rider=Prickett}, 1701771219853-2 {rider=Norem}, 1701771219858-0 {rider=Jones}, 1701771219858-1 {rider=Wood}, 1701771219859-0 {rider=Henshaw}]
StreamEntryID id6 = jedis.xadd("race:italy", new HashMap<String,String>(){{put("rider","Smith");}},XAddParams.xAddParams().maxLen(2));
List<StreamEntry> res37 = jedis.xrange("race:italy","-","+");
System.out.println(res37); // >>> [1701771067332-1 {rider=Henshaw}, 1701771067332-2 {rider=Smith}]
long res38 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10).exactTrimming());
System.out.println(res38); /// >>> 0
long res39 = jedis.xtrim("race:italy",XTrimParams.xTrimParams().maxLen(10));
System.out.println(res39); /// >>> 0
List<StreamEntry> res40 = jedis.xrange("race:italy","-","+");
System.out.println(res40); // >>> [1701771356428-2 {rider=Henshaw}, 1701771356429-0 {rider=Smith}]
long res41 = jedis.xdel("race:italy",id6);
System.out.println(res41); // >>> 1
List<StreamEntry> res42 = jedis.xrange("race:italy","-","+");
System.out.println(res42); // >>> [1701771517639-1 {rider=Henshaw}]
jedis.close();
}
}
package example_commands_test
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func ExampleClient_xadd() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
res1, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Castilla",
"speed": 30.2,
"position": 1,
"location_id": 1,
},
}).Result()
if err != nil {
panic(err)
}
// fmt.Println(res1) // >>> 1692632086370-0
res2, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Norem",
"speed": 28.8,
"position": 3,
"location_id": 1,
},
}).Result()
if err != nil {
panic(err)
}
// fmt.PrintLn(res2) // >>> 1692632094485-0
res3, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Prickett",
"speed": 29.7,
"position": 2,
"location_id": 1,
},
}).Result()
if err != nil {
panic(err)
}
// fmt.Println(res3) // >>> 1692632102976-0
xlen, err := rdb.XLen(ctx, "race:france").Result()
if err != nil {
panic(err)
}
fmt.Println(xlen) // >>> 3
}
func ExampleClient_racefrance1() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
_, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Castilla",
"speed": 30.2,
"position": 1,
"location_id": 1,
},
ID: "1692632086370-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Norem",
"speed": 28.8,
"position": 3,
"location_id": 1,
},
ID: "1692632094485-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Prickett",
"speed": 29.7,
"position": 2,
"location_id": 1,
},
ID: "1692632102976-0",
}).Result()
if err != nil {
panic(err)
}
res4, err := rdb.XRangeN(ctx, "race:france", "1691765278160-0", "+", 2).Result()
if err != nil {
panic(err)
}
fmt.Println(res4)
// >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla...
res5, err := rdb.XRead(ctx, &redis.XReadArgs{
Streams: []string{"race:france", "0"},
Count: 100,
Block: 300,
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res5)
// >>> // [{race:france [{1692632086370-0 map[location_id:1 position:1...
res6, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Castilla",
"speed": 29.9,
"position": 1,
"location_id": 2,
},
}).Result()
if err != nil {
panic(err)
}
//fmt.Println(res6) // >>> 1692632147973-0
res7, err := rdb.XLen(ctx, "race:france").Result()
if err != nil {
panic(err)
}
fmt.Println(res7) // >>> 4
}
func ExampleClient_raceusa() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
res8, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:usa",
Values: map[string]interface{}{
"racer": "Castilla",
},
ID: "0-1",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res8) // >>> 0-1
res9, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:usa",
Values: map[string]interface{}{
"racer": "Norem",
},
ID: "0-2",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res9) // >>> 0-2
res10, err := rdb.XAdd(ctx, &redis.XAddArgs{
Values: map[string]interface{}{
"racer": "Prickett",
},
ID: "0-1",
}).Result()
if err != nil {
// fmt.Println(err)
// >>> ERR The ID specified in XADD is equal or smaller than the target stream top item
}
res11, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:usa",
Values: map[string]interface{}{
"racer": "Prickett",
},
ID: "0-*",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res11) // >>> 0-3
}
func ExampleClient_racefrance2() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
_, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Castilla",
"speed": 30.2,
"position": 1,
"location_id": 1,
},
ID: "1692632086370-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Norem",
"speed": 28.8,
"position": 3,
"location_id": 1,
},
ID: "1692632094485-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Prickett",
"speed": 29.7,
"position": 2,
"location_id": 1,
},
ID: "1692632102976-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Castilla",
"speed": 29.9,
"position": 1,
"location_id": 2,
},
ID: "1692632147973-0",
}).Result()
if err != nil {
panic(err)
}
res12, err := rdb.XRange(ctx, "race:france", "-", "+").Result()
if err != nil {
panic(err)
}
fmt.Println(res12)
// >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla...
res13, err := rdb.XRange(ctx, "race:france",
"1692632086369", "1692632086371",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res13)
// >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0}]
res14, err := rdb.XRangeN(ctx, "race:france", "-", "+", 2).Result()
if err != nil {
panic(err)
}
fmt.Println(res14)
// >>> [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}]
res15, err := rdb.XRangeN(ctx, "race:france",
"(1692632094485-0", "+", 2,
).Result()
if err != nil {
panic(err)
}
fmt.Println(res15)
// >>> [{1692632102976-0 map[location_id:1 position:2 rider:Prickett speed:29.7] 0 0} {1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}]
res16, err := rdb.XRangeN(ctx, "race:france",
"(1692632147973-0", "+", 2,
).Result()
if err != nil {
panic(err)
}
fmt.Println(res16)
// >>> []
res17, err := rdb.XRevRangeN(ctx, "race:france", "+", "-", 1).Result()
if err != nil {
panic(err)
}
fmt.Println(res17)
// >>> [{1692632147973-0 map[location_id:2 position:1 rider:Castilla speed:29.9] 0 0}]
res18, err := rdb.XRead(ctx, &redis.XReadArgs{
Streams: []string{"race:france", "0"},
Count: 2,
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res18)
// >>> [{race:france [{1692632086370-0 map[location_id:1 position:1 rider:Castilla speed:30.2] 0 0} {1692632094485-0 map[location_id:1 position:3 rider:Norem speed:28.8] 0 0}]}]
}
func ExampleClient_xgroupcreate() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
_, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:france",
Values: map[string]interface{}{
"rider": "Castilla",
"speed": 30.2,
"position": 1,
"location_id": 1,
},
ID: "1692632086370-0",
}).Result()
if err != nil {
panic(err)
}
res19, err := rdb.XGroupCreate(ctx, "race:france", "france_riders", "$").Result()
if err != nil {
panic(err)
}
fmt.Println(res19) // >>> OK
}
func ExampleClient_xgroupcreatemkstream() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
res20, err := rdb.XGroupCreateMkStream(ctx,
"race:italy", "italy_riders", "$",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res20) // >>> OK
}
func ExampleClient_xgroupread() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
_, err := rdb.XGroupCreateMkStream(ctx,
"race:italy", "italy_riders", "$",
).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Castilla"},
}).Result()
// >>> 1692632639151-0
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Royce"},
}).Result()
// >>> 1692632647899-0
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Sam-Bodden"},
}).Result()
// >>> 1692632662819-0
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Prickett"},
}).Result()
// >>> 1692632670501-0
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Norem"},
}).Result()
// >>> 1692632678249-0
if err != nil {
panic(err)
}
// fmt.Println(res25)
res21, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
Streams: []string{"race:italy", ">"},
Group: "italy_riders",
Consumer: "Alice",
Count: 1,
}).Result()
if err != nil {
panic(err)
}
// fmt.Println(res21)
// >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}]
xlen, err := rdb.XLen(ctx, "race:italy").Result()
if err != nil {
panic(err)
}
fmt.Println(xlen)
}
func ExampleClient_raceitaly() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
_, err := rdb.XGroupCreateMkStream(ctx,
"race:italy", "italy_riders", "$",
).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Castilla"},
ID: "1692632639151-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Royce"},
ID: "1692632647899-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Sam-Bodden"},
ID: "1692632662819-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Prickett"},
ID: "1692632670501-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
Values: map[string]interface{}{"rider": "Norem"},
ID: "1692632678249-0",
}).Result()
if err != nil {
panic(err)
}
_, err = rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
Streams: []string{"race:italy", ">"},
Group: "italy_riders",
Consumer: "Alice",
Count: 1,
}).Result()
if err != nil {
panic(err)
}
res22, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
Streams: []string{"race:italy", "0"},
Group: "italy_riders",
Consumer: "Alice",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res22)
// >>> [{race:italy [{1692632639151-0 map[rider:Castilla] 0 0}]}]
res23, err := rdb.XAck(ctx,
"race:italy", "italy_riders", "1692632639151-0",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res23) // >>> 1
res24, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
Streams: []string{"race:italy", "0"},
Group: "italy_riders",
Consumer: "Alice",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res24)
// >>> [{race:italy []}]
res25, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
Streams: []string{"race:italy", ">"},
Group: "italy_riders",
Consumer: "Bob",
Count: 2,
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res25)
// >>> [{race:italy [{1692632647899-0 map[rider:Royce] 0 0} {1692632662819-0 map[rider:Sam-Bodden] 0 0}]}]
res26, err := rdb.XPending(ctx, "race:italy", "italy_riders").Result()
if err != nil {
panic(err)
}
fmt.Println(res26)
// >>> &{2 1692632647899-0 1692632662819-0 map[Bob:2]}
res27, err := rdb.XPendingExt(ctx, &redis.XPendingExtArgs{
Stream: "race:italy",
Group: "italy_riders",
Start: "-",
End: "+",
Count: 10,
}).Result()
if err != nil {
panic(err)
}
// fmt.Println(res27)
// >>> [{1692632647899-0 Bob 0s 1} {1692632662819-0 Bob 0s 1}]
res28, err := rdb.XRange(ctx, "race:italy",
"1692632647899-0", "1692632647899-0",
).Result()
if err != nil {
panic(err)
}
fmt.Println(res28) // >>> [{1692632647899-0 map[rider:Royce] 0 0}]
res29, err := rdb.XClaim(ctx, &redis.XClaimArgs{
Stream: "race:italy",
Group: "italy_riders",
Consumer: "Alice",
MinIdle: 0,
Messages: []string{"1692632647899-0"},
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res29)
res30, res30a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{
Stream: "race:italy",
Group: "italy_riders",
Consumer: "Alice",
Start: "0-0",
Count: 1,
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res30) // >>> [{1692632647899-0 map[rider:Royce] 0 0}]
fmt.Println(res30a) // >>> 1692632662819-0
res31, res31a, err := rdb.XAutoClaim(ctx, &redis.XAutoClaimArgs{
Stream: "race:italy",
Group: "italy_riders",
Consumer: "Lora",
Start: "(1692632662819-0",
Count: 1,
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res31) // >>> []
fmt.Println(res31a) // >>> 0-0
res32, err := rdb.XInfoStream(ctx, "race:italy").Result()
if err != nil {
panic(err)
}
fmt.Println(res32.Length)
// >>> 5
fmt.Println(res32.FirstEntry)
// >>> {1692632639151-0 map[rider:Castilla] 0 0}
res33, err := rdb.XInfoGroups(ctx, "race:italy").Result()
if err != nil {
panic(err)
}
fmt.Println(res33)
// >>> [{italy_riders 3 2 1692632662819-0 3 2}]
res34, err := rdb.XInfoConsumers(ctx, "race:italy", "italy_riders").Result()
if err != nil {
panic(err)
}
// fmt.Println(res34)
// >>> [{Alice 1 1ms 1ms} {Bob 1 2ms 2ms} {Lora 0 1ms -1ms}]
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
MaxLen: 2,
Values: map[string]interface{}{"rider": "Jones"},
},
).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
MaxLen: 2,
Values: map[string]interface{}{"rider": "Wood"},
},
).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
MaxLen: 2,
Values: map[string]interface{}{"rider": "Henshaw"},
},
).Result()
if err != nil {
panic(err)
}
res35, err := rdb.XLen(ctx, "race:italy").Result()
if err != nil {
panic(err)
}
fmt.Println(res35) // >>> 2
res36, err := rdb.XRange(ctx, "race:italy", "-", "+").Result()
if err != nil {
panic(err)
}
// fmt.Println(res36)
// >>> [{1726649529170-1 map[rider:Wood] 0 0} {1726649529171-0 map[rider:Henshaw] 0 0}]
res37, err := rdb.XTrimMaxLen(ctx, "race:italy", 10).Result()
if err != nil {
panic(err)
}
fmt.Println(res37) // >>> 0
res38, err := rdb.XTrimMaxLenApprox(ctx, "race:italy", 10, 20).Result()
if err != nil {
panic(err)
}
fmt.Println(res38) // >>> 0
}
func ExampleClient_xdel() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})
_, err := rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
MaxLen: 2,
Values: map[string]interface{}{"rider": "Wood"},
ID: "1692633198206-0",
},
).Result()
if err != nil {
panic(err)
}
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: "race:italy",
MaxLen: 2,
Values: map[string]interface{}{"rider": "Henshaw"},
ID: "1692633208557-0",
},
).Result()
if err != nil {
panic(err)
}
res39, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result()
if err != nil {
panic(err)
}
fmt.Println(res39)
// >>> [{1692633198206-0 map[rider:Wood] 0 0} {1692633208557-0 map[rider:Henshaw] 0 0}]
res40, err := rdb.XDel(ctx, "race:italy", "1692633208557-0").Result()
if err != nil {
panic(err)
}
fmt.Println(res40) // 1
res41, err := rdb.XRangeN(ctx, "race:italy", "-", "+", 2).Result()
if err != nil {
panic(err)
}
fmt.Println(res41)
// >>> [{1692633198206-0 map[rider:Wood] 0 0}]
}
using NRedisStack.Tests;
using StackExchange.Redis;
public class StreamTutorial
{
public void Run()
{
var muxer = ConnectionMultiplexer.Connect("localhost:6379");
var db = muxer.GetDatabase();
RedisValue res1 = db.StreamAdd(
"race:france",
[
new("rider", "Castilla"),
new("speed", 30.2),
new("position", 1),
new("location_id", 1)
]
);
Console.WriteLine(res1); // >>> 1712668482289-0
RedisValue res2 = db.StreamAdd(
"race:france",
[
new("rider", "Norem"),
new("speed", 28.8),
new("position", 3),
new("location_id", 1)
]
);
Console.WriteLine(res2); // >>> 1712668766534-1
RedisValue res3 = db.StreamAdd(
"race:france",
[
new("rider", "Prickett"),
new("speed", 29.7),
new("position", 2),
new("location_id", 1)
]
);
Console.WriteLine(res3); // >>> 1712669055705-0
// Tests for 'xadd' step.
StreamEntry[] res4 = db.StreamRange("race:france", "1712668482289-0", "+", 2);
foreach (StreamEntry entry in res4)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1]
// >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1]
// Tests for 'xrange' step.
StreamEntry[] res5 = db.StreamRead("race:france", 0, 100);
foreach (StreamEntry entry in res4)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1]
// >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1]
// >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1]
// Tests for 'xread_block' step.
RedisValue res6 = db.StreamAdd(
"race:france",
[
new("rider", "Castilla"),
new("speed", 29.9),
new("position", 1),
new("location_id", 2)
]
);
Console.WriteLine(res6); // >>> 1712675674750-0
// Tests for 'xadd_2' step.
long res7 = db.StreamLength("race:france");
Console.WriteLine(res7); // >>> 4
// Tests for 'xlen' step.
RedisValue res8 = db.StreamAdd(
"race:usa",
[
new("racer", "Castilla")
],
"0-1"
);
Console.WriteLine(res8); // >>> 0-1
RedisValue res9 = db.StreamAdd(
"race:usa",
[
new("racer", "Norem")
],
"0-2"
);
Console.WriteLine(res9); // >>> 0-2
// Tests for 'xadd_id' step.
try
{
RedisValue res10 = db.StreamAdd(
"race:usa",
[
new("racer", "Prickett")
],
"0-1"
);
}
catch (RedisServerException ex)
{
Console.WriteLine(ex); // >>> ERR The ID specified in XADD is equal or smaller than the target stream top item
}
// Tests for 'xadd_bad_id' step.
RedisValue res11 = "";
Version version = muxer.GetServer("localhost:6379").Version;
if (version.Major >= 7)
{
res11 = db.StreamAdd(
"race:usa",
[
new("rider", "Norem")
],
"0-*"
);
Console.WriteLine(res11); // >>> "0-3"
}
// Tests for 'xadd_7' step.
StreamEntry[] res12 = db.StreamRange("race:france", "-", "+");
foreach (StreamEntry entry in res12)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1]
// >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1]
// >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1]
// >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2]
// Tests for 'xrange_all' step.
StreamEntry[] res13 = db.StreamRange("race:france", 1712668482289, 1712668482291);
foreach (StreamEntry entry in res13)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1]
// Tests for 'xrange_time' step.
StreamEntry[] res14 = db.StreamRange("race:france", "-", "+", 2);
foreach (StreamEntry entry in res14)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1]
// >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1]
// Tests for 'xrange_step_1' step.
StreamEntry[] res15 = db.StreamRange("race:france", "(1712668766534-1", "+", 2);
foreach (StreamEntry entry in res15)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712669055705-0: [rider: Prickett, speed: 29.699999999999999, position: 2, location_id: 1]
// >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2]
// Tests for 'xrange_step_2' step.
StreamEntry[] res16 = db.StreamRange("race:france", "(1712675674750-0", "+", 2);
foreach (StreamEntry entry in res16)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> <empty array>
// Tests for 'xrange_empty' step.
StreamEntry[] res17 = db.StreamRange("race:france", "+", "-", 1, Order.Descending);
foreach (StreamEntry entry in res17)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712675674750-0: [rider: Castilla, speed: 29.899999999999999, position: 1, location_id: 2]
// Tests for 'xrevrange' step.
StreamEntry[] res18 = db.StreamRead("race:france", 0, 2);
foreach (StreamEntry entry in res18)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712668482289-0: [rider: Castilla, speed: 30.199999999999999, position: 1, location_id: 1]
// >>> 1712668766534-1: [rider: Norem, speed: 28.800000000000001, position: 3, location_id: 1]
// Tests for 'xread' step.
bool res19 = db.StreamCreateConsumerGroup("race:france", "france_riders", "$");
Console.WriteLine(res19); // >>> true
// Tests for 'xgroup_create' step.
bool res20 = db.StreamCreateConsumerGroup("race:italy", "italy_riders", "$", true);
Console.WriteLine(res20); // >>> true
// Tests for 'xgroup_create_mkstream' step.
RedisValue groupRes = db.StreamAdd(
"race:italy",
[new("rider", "Castilla")]
); // 1712744323758-0
groupRes = db.StreamAdd(
"race:italy",
[new("rider", "Royce")]
); // 1712744358384-0
groupRes = db.StreamAdd(
"race:italy",
[new("rider", "Sam-Bodden")]
); // 1712744379676-0
groupRes = db.StreamAdd(
"race:italy",
[new("rider", "Prickett")]
); // 1712744399401-0
groupRes = db.StreamAdd(
"race:italy",
[new("rider", "Norem")]
); // 1712744413117-0
StreamEntry[] res21 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", ">", 1);
foreach (StreamEntry entry in res21)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712744323758-0: [rider: Castilla]
// Tests for 'xgroup_read' step.
StreamEntry[] res22 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0");
foreach (StreamEntry entry in res22)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
// >>> 1712744323758-0: [rider: Castilla]
}
// Tests for 'xgroup_read_id' step.
long res23 = db.StreamAcknowledge("race:italy", "italy_riders", "1712744323758-0");
Console.WriteLine(res23); // >>> 1
StreamEntry[] res24 = db.StreamReadGroup("race:italy", "italy_riders", "Alice", "0");
foreach (StreamEntry entry in res24)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> <empty array>
// Tests for 'xack' step.
StreamEntry[] res25 = db.StreamReadGroup("race:italy", "italy_riders", "Bob", ">", 2);
foreach (StreamEntry entry in res25)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712744358384-0: [rider: Royce]
// >>> 1712744379676-0: [rider: Sam-Bodden]
// Tests for 'xgroup_read_bob' step.
StreamPendingInfo res26 = db.StreamPending("race:italy", "italy_riders");
Console.WriteLine($"pending: {res26.PendingMessageCount}, min: {res26.LowestPendingMessageId}, max: {res26.HighestPendingMessageId}, consumers:[{string.Join(", ", res26.Consumers.Select(c => $"{c.Name}: {c.PendingMessageCount}"))}]");
// >>> pending: 2, min: 1712747506906-0, max: 1712747506907-0, consumers:[name: Bob, pending:2]
// Tests for 'xpending' step.
StreamPendingMessageInfo[] res27 = db.StreamPendingMessages(
"race:italy", "italy_riders", 10, "", "-", "+"
);
foreach (StreamPendingMessageInfo info in res27)
{
Console.WriteLine($"message_id: {info.MessageId}, consumer: {info.ConsumerName}, time_since_delivered: {info.IdleTimeInMilliseconds}, times_delivered: {info.DeliveryCount}");
}
// >>> message_id: min: 1712747506906-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1
// >>> message_id: min: 1712747506907-0, consumer: Bob, time_since_delivered: 31084, times_delivered: 1
// Tests for 'xpending_plus_minus' step.
StreamEntry[] res28 = db.StreamRange("race:italy", "1712744358384-0", "1712744358384-0");
foreach (StreamEntry entry in res28)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712744358384-0: [rider: Royce]
// Tests for 'xrange_pending' step.
StreamEntry[] res29 = db.StreamClaim(
"race:italy", "italy_riders", "Alice", 60000, [1712744358384 - 0]
);
foreach (StreamEntry entry in res29)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712744358384-0: [rider: Royce]
// Tests for 'xclaim' step.
StreamAutoClaimResult res30 = db.StreamAutoClaim(
"race:italy", "italy_riders", "Alice", 1, "0-0", 1
);
Console.WriteLine($"{res30.NextStartId}, ({string.Join(", ", res30.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})");
// >>> 1712744379676-0, (1712744358384-0: [rider: Royce])
// Tests for 'xautoclaim' step.
StreamAutoClaimResult res31 = db.StreamAutoClaim(
"race:italy", "italy_riders", "Alice", 1, "(1712744358384-0", 1
);
Console.WriteLine($"{res31.NextStartId}, ({string.Join(", ", res31.ClaimedEntries.Select(entry => $"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"))})");
// >>> 0-0, (1712744379676-0: [rider: Sam-Bodden])
// Tests for 'xautoclaim_cursor' step.
StreamInfo res32 = db.StreamInfo("race:italy");
Console.WriteLine($"length: {res32.Length}, radix-tree-keys: {res32.RadixTreeKeys}, radix-tree-nodes: {res32.RadixTreeNodes}, last-generated-id: {res32.LastGeneratedId}, first-entry: {$"{res32.FirstEntry.Id}: [{string.Join(", ", res32.FirstEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}, last-entry: {$"{res32.LastEntry.Id}: [{string.Join(", ", res32.LastEntry.Values.Select(b => $"{b.Name}: {b.Value}"))}]"}");
// >>> length: 5, radix-tree-keys: 1, radix-tree-nodes: 2, last-generated-id: 1712756762686-1, first-entry: 1712756762685-0: [rider: Castilla], last-entry: 1712756762686-1: [rider: Norem]
// Tests for 'xinfo' step.
StreamGroupInfo[] res33 = db.StreamGroupInfo("race:italy");
foreach (StreamGroupInfo info in res33)
{
Console.WriteLine($"name: {info.Name}, consumers: {info.ConsumerCount}, pending: {info.PendingMessageCount}, last-delivered-id: {info.LastDeliveredId}");
}
// >>> name: italy_riders, consumers: 2, pending: 2, last-delivered-id: 1712757192730-2
// Tests for 'xinfo_groups' step.
StreamConsumerInfo[] res34 = db.StreamConsumerInfo("race:italy", "italy_riders");
foreach (StreamConsumerInfo info in res34)
{
Console.WriteLine($"name: {info.Name}, pending: {info.PendingMessageCount}, idle: {info.IdleTimeInMilliseconds}");
}
// >>> name: Alice, pending: 1, idle: 7717
// >>> name: Bob, pending: 0, idle: 7722
// Tests for 'xinfo_consumers' step.
db.StreamAdd(
"race:italy", [new("rider", "Jones")], null, 2, true
);
db.StreamAdd(
"race:italy", [new("rider", "Wood")], null, 2, true
);
db.StreamAdd(
"race:italy", [new("rider", "Henshaw")], null, 2, true
);
long res35 = db.StreamLength("race:italy");
Console.WriteLine(res35); // >>> 8
StreamEntry[] res36 = db.StreamRange("race:italy", "-", "+");
foreach (StreamEntry entry in res36)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712758336128-0: [rider: Castilla]
// >>> 1712758336128-1: [rider: Royce]
// >>> 1712758336128-2: [rider: Sam-Bodden]
// >>> 1712758336129-0: [rider: Prickett]
// >>> 1712758336139-0: [rider: Norem]
// >>> 1712758340854-0: [rider: Jones]
// >>> 1712758341645-0: [rider: Wood]
// >>> 1712758342134-0: [rider: Henshaw]
db.StreamAdd(
"race:italy", [new("rider", "Smith")], null, 2, false
);
StreamEntry[] res37 = db.StreamRange("race:italy", "-", "+");
foreach (StreamEntry entry in res37)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// 1712758746476-1: [rider: Henshaw]
// 1712758746477-0: [rider: Smith]
// Tests for 'maxlen' step.
long res38 = db.StreamTrim("race:italy", 10, false);
Console.WriteLine(res38); // >>> 0
// Tests for 'xtrim' step.
long res39 = db.StreamTrim("race:italy", 10, true);
Console.WriteLine(res39); // >>> 0
// Tests for 'xtrim2' step.
StreamEntry[] res40 = db.StreamRange("race:italy", "-", "+");
foreach (StreamEntry entry in res40)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712759694003-0: [rider: Henshaw]
// >>> 1712759694003-1: [rider: Smith]
long res41 = db.StreamDelete("race:italy", ["1712759694003-1"]);
Console.WriteLine(res41); // >>> 1
StreamEntry[] res42 = db.StreamRange("race:italy", "-", "+");
foreach (StreamEntry entry in res42)
{
Console.WriteLine($"{entry.Id}: [{string.Join(", ", entry.Values.Select(b => $"{b.Name}: {b.Value}"))}]");
}
// >>> 1712759694003-0: [rider: Henshaw]
// Tests for 'xdel' step.
}
}
require 'redis'
r = Redis.new
res1 = r.xadd('race:france', {
'rider' => 'Castilla',
'speed' => 30.2,
'position' => 1,
'location_id' => 1
})
puts res1 # 1692632086370-0, for example
res2 = r.xadd('race:france', {
'rider' => 'Norem',
'speed' => 28.8,
'position' => 3,
'location_id' => 1
})
puts res2 # 1692632094485-0, for example
res3 = r.xadd('race:france', {
'rider' => 'Prickett',
'speed' => 29.7,
'position' => 2,
'location_id' => 1
})
puts res3 # 1692632102976-0, for example
r.del('race:france')
r.xadd('race:france', {
'rider' => 'Castilla',
'speed' => '30.2',
'position' => '1',
'location_id' => '1'
}, id: '1692632086370-0')
r.xadd('race:france', {
'rider' => 'Norem',
'speed' => '28.8',
'position' => '3',
'location_id' => '1'
}, id: '1692632094485-0')
r.xadd('race:france', {
'rider' => 'Prickett',
'speed' => '29.7',
'position' => '2',
'location_id' => '1'
}, id: '1692632102976-0')
r.xadd('race:france', {
'rider' => 'Castilla',
'speed' => '29.9',
'position' => '1',
'location_id' => '2'
}, id: '1692632147973-0')
res4 = r.xrange('race:france', '1692632086370-0', '+', count: 2)
puts res4.inspect
# [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}],
# ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]]
r.del('race:france')
r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0')
res5 = r.xread(['race:france'], ['$'], count: 100, block: 300)
puts res5.inspect # {}
res6 = r.xadd('race:france', {
'rider' => 'Castilla',
'speed' => 29.9,
'position' => 1,
'location_id' => 2
})
puts res6 # 1692632147973-0, for example
r.del('race:france')
r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0')
r.xadd('race:france', {'rider' => 'Norem'}, id: '1692632094485-0')
r.xadd('race:france', {'rider' => 'Prickett'}, id: '1692632102976-0')
r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632147973-0')
res7 = r.xlen('race:france')
puts res7 # 4
r.del('race:usa')
res8 = r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1')
puts res8 # 0-1
res9 = r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2')
puts res9 # 0-2
begin
r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-1')
rescue Redis::CommandError => e
puts e.message
# ERR The ID specified in XADD is equal or smaller than the target stream top item
end
r.del('race:usa')
r.xadd('race:usa', {'racer' => 'Castilla'}, id: '0-1')
r.xadd('race:usa', {'racer' => 'Norem'}, id: '0-2')
res10 = r.xadd('race:usa', {'racer' => 'Prickett'}, id: '0-*')
puts res10 # 0-3
r.del('race:france')
r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0')
r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0')
r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0')
r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0')
res11 = r.xrange('race:france', '-', '+')
puts res11.inspect
# [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}],
# ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}],
# ["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}],
# ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]]
r.del('race:france')
r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0')
r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0')
res12 = r.xrange('race:france', '1692632086369', '1692632086371')
puts res12.inspect
# [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}]]
r.del('race:france')
r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0')
r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0')
r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0')
r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0')
res13 = r.xrange('race:france', '-', '+', count: 2)
puts res13.inspect
# [["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}],
# ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]]
r.del('race:france')
r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '30.2', 'position' => '1', 'location_id' => '1'}, id: '1692632086370-0')
r.xadd('race:france', {'rider' => 'Norem', 'speed' => '28.8', 'position' => '3', 'location_id' => '1'}, id: '1692632094485-0')
r.xadd('race:france', {'rider' => 'Prickett', 'speed' => '29.7', 'position' => '2', 'location_id' => '1'}, id: '1692632102976-0')
r.xadd('race:france', {'rider' => 'Castilla', 'speed' => '29.9', 'position' => '1', 'location_id' => '2'}, id: '1692632147973-0')
res14 = r.xrange('race:france', '(1692632094485-0', '+', count: 2)
puts res14.inspect
# [["1692632102976-0", {"rider"=>"Prickett", "speed"=>"29.7", "position"=>"2", "location_id"=>"1"}],
# ["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]]
res15 = r.xrange('race:france', '(1692632147973-0', '+', count: 2)
puts res15.inspect # []
res16 = r.xrevrange('race:france', '+', '-', count: 1)
puts res16.inspect
# [["1692632147973-0", {"rider"=>"Castilla", "speed"=>"29.9", "position"=>"1", "location_id"=>"2"}]]
res17 = r.xread(['race:france'], ['0'], count: 2)
puts res17.inspect
# {"race:france"=>[["1692632086370-0", {"rider"=>"Castilla", "speed"=>"30.2", "position"=>"1", "location_id"=>"1"}],
# ["1692632094485-0", {"rider"=>"Norem", "speed"=>"28.8", "position"=>"3", "location_id"=>"1"}]]}
r.del('race:france')
r.xadd('race:france', {'rider' => 'Castilla'}, id: '1692632086370-0')
res18 = r.xgroup(:create, 'race:france', 'france_riders', '$')
puts res18 # OK
r.del('race:italy')
res19 = r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true)
puts res19 # OK
r.del('race:italy')
r.xgroup(:create, 'race:italy', 'italy_riders', '$', mkstream: true)
r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0')
r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0')
r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0')
r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0')
r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0')
res20 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['>'], count: 1)
puts res20.inspect
# {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]}
res21 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0'], count: 1)
puts res21.inspect
# {"race:italy"=>[["1692632639151-0", {"rider"=>"Castilla"}]]}
res22 = r.xack('race:italy', 'italy_riders', '1692632639151-0')
puts res22 # 1
res23 = r.xreadgroup('italy_riders', 'Alice', ['race:italy'], ['0'])
puts res23.inspect
# {"race:italy"=>[]}
res24 = r.xreadgroup('italy_riders', 'Bob', ['race:italy'], ['>'], count: 2)
puts res24.inspect
# {"race:italy"=>[["1692632647899-0", {"rider"=>"Royce"}],
# ["1692632662819-0", {"rider"=>"Sam-Bodden"}]]}
res25 = r.xpending('race:italy', 'italy_riders')
puts res25.inspect
# {"size"=>2, "min_entry_id"=>"1692632647899-0", "max_entry_id"=>"1692632662819-0", "consumers"=>{"Bob"=>"2"}}
res26 = r.xpending('race:italy', 'italy_riders', '-', '+', 10)
puts res26.inspect
res27 = r.xrange('race:italy', '1692632647899-0', '1692632647899-0')
puts res27.inspect
# [["1692632647899-0", {"rider"=>"Royce"}]]
res28 = r.xclaim('race:italy', 'italy_riders', 'Alice', 0, '1692632647899-0')
puts res28.inspect
# [["1692632647899-0", {"rider"=>"Royce"}]]
res29 = r.xautoclaim('race:italy', 'italy_riders', 'Alice', 0, '0-0', count: 1)
puts res29.inspect
# {"next"=>"1692632662819-0", "entries"=>[["1692632647899-0", {"rider"=>"Royce"}]]}
res30 = r.xautoclaim('race:italy', 'italy_riders', 'Lora', 0, res29['next'], count: 1)
puts res30.inspect
# {"next"=>"0-0", "entries"=>[["1692632662819-0", {"rider"=>"Sam-Bodden"}]]}
res31 = r.xinfo(:stream, 'race:italy')
puts res31.inspect
res32 = r.xinfo(:groups, 'race:italy')
puts res32.inspect
res33 = r.xinfo(:consumers, 'race:italy', 'italy_riders')
puts res33.inspect
r.del('race:italy')
r.xadd('race:italy', {'rider' => 'Castilla'}, id: '1692632639151-0')
r.xadd('race:italy', {'rider' => 'Royce'}, id: '1692632647899-0')
r.xadd('race:italy', {'rider' => 'Sam-Bodden'}, id: '1692632662819-0')
r.xadd('race:italy', {'rider' => 'Prickett'}, id: '1692632670501-0')
r.xadd('race:italy', {'rider' => 'Norem'}, id: '1692632678249-0')
r.xadd('race:italy', {'rider' => 'Jones'}, id: '1692633189161-0', maxlen: 2)
r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0', maxlen: 2)
r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0', maxlen: 2)
res34 = r.xlen('race:italy')
puts res34 # 2
res35 = r.xrange('race:italy', '-', '+')
puts res35.inspect
# [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]]
res36 = r.xtrim('race:italy', 10, approximate: false)
puts res36 # 0
r.del('mystream')
1.upto(10) do |n|
r.xadd('mystream', {'field' => 'value'}, id: "#{n}-0")
end
res37 = r.xtrim('mystream', 10, approximate: true)
puts res37 # 0
r.del('race:italy')
r.xadd('race:italy', {'rider' => 'Wood'}, id: '1692633198206-0')
r.xadd('race:italy', {'rider' => 'Henshaw'}, id: '1692633208557-0')
res38 = r.xrange('race:italy', '-', '+', count: 2)
puts res38.inspect
# [["1692633198206-0", {"rider"=>"Wood"}], ["1692633208557-0", {"rider"=>"Henshaw"}]]
res39 = r.xdel('race:italy', '1692633208557-0')
puts res39 # 1
res40 = r.xrange('race:italy', '-', '+', count: 2)
puts res40.inspect
# [["1692633198206-0", {"rider"=>"Wood"}]]
mod stream_tests {
use redis::{
streams::{
StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply,
StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply,
StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode,
StreamTrimOptions,
},
Commands,
};
use std::{thread::sleep, time::Duration};
fn delete_keys(r: &mut redis::Connection, keys: &[&str]) {
let _: usize = r.del(keys).unwrap_or(0);
}
fn add_france_fixed(r: &mut redis::Connection) {
delete_keys(r, &["race:france"]);
let _: Option<String> = r
.xadd(
"race:france",
"1692632086370-0",
&[
("rider", "Castilla"),
("speed", "30.2"),
("position", "1"),
("location_id", "1"),
],
)
.expect("add france 1");
let _: Option<String> = r
.xadd(
"race:france",
"1692632094485-0",
&[
("rider", "Norem"),
("speed", "28.8"),
("position", "3"),
("location_id", "1"),
],
)
.expect("add france 2");
let _: Option<String> = r
.xadd(
"race:france",
"1692632102976-0",
&[
("rider", "Prickett"),
("speed", "29.7"),
("position", "2"),
("location_id", "1"),
],
)
.expect("add france 3");
let _: Option<String> = r
.xadd(
"race:france",
"1692632147973-0",
&[
("rider", "Castilla"),
("speed", "29.9"),
("position", "1"),
("location_id", "2"),
],
)
.expect("add france 4");
}
fn seed_usa_fixed(r: &mut redis::Connection) {
delete_keys(r, &["race:usa"]);
let _: Option<String> = r
.xadd("race:usa", "0-1", &[("racer", "Castilla")])
.expect("add usa 1");
let _: Option<String> = r
.xadd("race:usa", "0-2", &[("racer", "Norem")])
.expect("add usa 2");
}
fn seed_italy_group_base(r: &mut redis::Connection) {
delete_keys(r, &["race:italy"]);
let _: () = r
.xgroup_create_mkstream("race:italy", "italy_riders", "$")
.expect("create italy group");
let _: Option<String> = r
.xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")])
.expect("add italy 1");
let _: Option<String> = r
.xadd("race:italy", "1692632647899-0", &[("rider", "Royce")])
.expect("add italy 2");
let _: Option<String> = r
.xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")])
.expect("add italy 3");
let _: Option<String> = r
.xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")])
.expect("add italy 4");
let _: Option<String> = r
.xadd("race:italy", "1692632678249-0", &[("rider", "Norem")])
.expect("add italy 5");
}
fn seed_italy_alice_pending(r: &mut redis::Connection) {
seed_italy_group_base(r);
let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1);
let _: Option<StreamReadReply> = r
.xread_options(&["race:italy"], &[">"], &opts)
.expect("alice read pending");
}
fn seed_italy_after_ack(r: &mut redis::Connection) {
seed_italy_alice_pending(r);
let _: usize = r
.xack("race:italy", "italy_riders", &["1692632639151-0"])
.expect("ack first italy message");
}
fn seed_italy_bob_pending(r: &mut redis::Connection) {
seed_italy_after_ack(r);
let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2);
let _: Option<StreamReadReply> = r
.xread_options(&["race:italy"], &[">"], &opts)
.expect("bob read pending");
}
fn seed_italy_info_state(r: &mut redis::Connection) {
seed_italy_bob_pending(r);
sleep(Duration::from_millis(5));
let _: redis::streams::StreamClaimReply = r
.xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"])
.expect("alice claim");
sleep(Duration::from_millis(5));
let _: redis::streams::StreamClaimReply = r
.xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"])
.expect("lora claim");
}
fn seed_trim_stream(r: &mut redis::Connection) {
delete_keys(r, &["mystream"]);
for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] {
let _: Option<String> = r
.xadd("mystream", id, &[("field", "value")])
.expect("seed mystream");
}
}
fn run() {
let mut r = match redis::Client::open("redis://127.0.0.1") {
Ok(client) => match client.get_connection() {
Ok(conn) => conn,
Err(e) => {
println!("Failed to connect to Redis: {e}");
return;
}
},
Err(e) => {
println!("Failed to create Redis client: {e}");
return;
}
};
let res1 = {
let res: Option<String> = r
.xadd(
"race:france",
"*",
&[
("rider", "Castilla"),
("speed", "30.2"),
("position", "1"),
("location_id", "1"),
],
)
.expect("xadd 1");
res.expect("missing stream id")
};
println!("{res1}"); // >>> 1692632086370-0
let res2 = {
let res: Option<String> = r
.xadd(
"race:france",
"*",
&[
("rider", "Norem"),
("speed", "28.8"),
("position", "3"),
("location_id", "1"),
],
)
.expect("xadd 2");
res.expect("missing stream id")
};
println!("{res2}"); // >>> 1692632094485-0
let res3 = {
let res: Option<String> = r
.xadd(
"race:france",
"*",
&[
("rider", "Prickett"),
("speed", "29.7"),
("position", "2"),
("location_id", "1"),
],
)
.expect("xadd 3");
res.expect("missing stream id")
};
println!("{res3}"); // >>> 1692632102976-0
add_france_fixed(&mut r);
if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2) {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])]
}
add_france_fixed(&mut r);
let opts = StreamReadOptions::default().count(100).block(300);
if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts) {
let res: Option<StreamReadReply> = res;
println!("{res:?}"); // >>> None
}
if let Ok(res) = r.xadd(
"race:france",
"*",
&[
("rider", "Castilla"),
("speed", "29.9"),
("position", "1"),
("location_id", "2"),
],
) {
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 1692632147973-0
}
add_france_fixed(&mut r);
if let Ok(res) = r.xlen("race:france") {
let res: usize = res;
println!("{res}"); // >>> 4
}
delete_keys(&mut r, &["race:usa"]);
if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]) {
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 0-1
}
if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]) {
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 0-2
}
let res: redis::RedisResult<Option<String>> =
r.xadd("race:usa", "0-1", &[("racer", "Prickett")]);
match res {
Ok(_) => {}
Err(e) => {
let msg = e.to_string();
println!("{msg}");
// >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item
}
}
seed_usa_fixed(&mut r);
if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]) {
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 0-3
}
add_france_fixed(&mut r);
if let Ok(res) = r.xrange_all("race:france") {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])]
}
add_france_fixed(&mut r);
if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371") {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])]
}
add_france_fixed(&mut r);
if let Ok(res) = r.xrange_count("race:france", "-", "+", 2) {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])]
}
add_france_fixed(&mut r);
if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2) {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])]
}
add_france_fixed(&mut r);
if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2) {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}"); // >>> []
}
add_france_fixed(&mut r);
if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1) {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])]
}
add_france_fixed(&mut r);
let opts = StreamReadOptions::default().count(2);
if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts) {
let res: Option<StreamReadReply> = res;
let reply = res.expect("xread should return data");
let view: Vec<_> = reply
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])]
}
add_france_fixed(&mut r);
if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$") {
let res: () = res;
let _ = res;
println!("OK"); // >>> OK
}
delete_keys(&mut r, &["race:italy"]);
if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$") {
let res: () = res;
let _ = res;
println!("OK"); // >>> OK
}
delete_keys(&mut r, &["race:italy"]);
let _: () = r
.xgroup_create_mkstream("race:italy", "italy_riders", "$")
.expect("create italy group");
let italy_1: Option<String> = r
.xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")])
.expect("italy1");
let italy_1 = italy_1.expect("missing stream id");
println!("{italy_1}"); // >>> 1692632639151-0
let italy_2: Option<String> = r
.xadd("race:italy", "1692632647899-0", &[("rider", "Royce")])
.expect("italy2");
let italy_2 = italy_2.expect("missing stream id");
println!("{italy_2}"); // >>> 1692632647899-0
let italy_3: Option<String> = r
.xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")])
.expect("italy3");
let italy_3 = italy_3.expect("missing stream id");
println!("{italy_3}"); // >>> 1692632662819-0
let italy_4: Option<String> = r
.xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")])
.expect("italy4");
let italy_4 = italy_4.expect("missing stream id");
println!("{italy_4}"); // >>> 1692632670501-0
let italy_5: Option<String> = r
.xadd("race:italy", "1692632678249-0", &[("rider", "Norem")])
.expect("italy5");
let italy_5 = italy_5.expect("missing stream id");
println!("{italy_5}"); // >>> 1692632678249-0
let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1);
if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("xgroup read should return data")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])]
}
seed_italy_alice_pending(&mut r);
let opts = StreamReadOptions::default().group("italy_riders", "Alice");
if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("xgroup history")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])]
}
seed_italy_alice_pending(&mut r);
if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]) {
let res: usize = res;
println!("{res}"); // >>> 1
}
let opts = StreamReadOptions::default().group("italy_riders", "Alice");
if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts) {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("xgroup history")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}"); // >>> [("race:italy", [])]
}
seed_italy_after_ack(&mut r);
let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2);
if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts) {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("bob should receive data")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])]
}
seed_italy_bob_pending(&mut r);
if let Ok(res) = r.xpending("race:italy", "italy_riders") {
let res: StreamPendingReply = res;
let view = match res {
StreamPendingReply::Empty => None,
StreamPendingReply::Data(data) => Some((
data.count,
data.start_id.clone(),
data.end_id.clone(),
data.consumers
.iter()
.map(|consumer| (consumer.name.clone(), consumer.pending))
.collect::<Vec<_>>(),
)),
}
.expect("pending summary");
println!("{view:?}");
// >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)])
}
seed_italy_bob_pending(&mut r);
sleep(Duration::from_millis(5));
if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10) {
let res: StreamPendingCountReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
entry.consumer.clone(),
entry.last_delivered_ms,
entry.times_delivered,
)
})
.collect();
println!("{view:?}");
// >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)]
}
seed_italy_bob_pending(&mut r);
if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0") {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])]
}
seed_italy_bob_pending(&mut r);
sleep(Duration::from_millis(5));
if let Ok(res) = r.xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"]) {
let res: redis::streams::StreamClaimReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])]
}
seed_italy_bob_pending(&mut r);
sleep(Duration::from_millis(5));
let opts = StreamAutoClaimOptions::default().count(1);
if let Ok(res) = r.xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts) {
let res: redis::streams::StreamAutoClaimReply = res;
let claimed: Vec<_> = res
.claimed
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{:?}", (res.next_stream_id.clone(), &claimed));
// >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])])
}
seed_italy_bob_pending(&mut r);
sleep(Duration::from_millis(5));
let first_opts = StreamAutoClaimOptions::default().count(1);
let _: redis::streams::StreamAutoClaimReply = r
.xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts)
.expect("first autoclaim");
let next_opts = StreamAutoClaimOptions::default().count(1);
if let Ok(res) = r.xautoclaim_options(
"race:italy",
"italy_riders",
"Lora",
1,
"(1692632647899-0",
next_opts,
) {
let res: redis::streams::StreamAutoClaimReply = res;
let claimed: Vec<_> = res
.claimed
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{:?}", (res.next_stream_id.clone(), &claimed));
// >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])])
}
seed_italy_info_state(&mut r);
if let Ok(res) = r.xinfo_stream("race:italy") {
let res: StreamInfoStreamReply = res;
let view = (
res.length,
res.radix_tree_keys,
res.groups,
res.last_generated_id.clone(),
res.first_entry.id.clone(),
res.last_entry.id.clone(),
);
println!("{view:?}");
// >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0")
}
seed_italy_info_state(&mut r);
if let Ok(res) = r.xinfo_groups("race:italy") {
let res: StreamInfoGroupsReply = res;
let view: Vec<_> = res
.groups
.iter()
.map(|group| {
(
group.name.clone(),
group.consumers,
group.pending,
group.last_delivered_id.clone(),
)
})
.collect();
println!("{view:?}");
// >>> [("italy_riders", 3, 2, "1692632662819-0")]
}
seed_italy_info_state(&mut r);
if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders") {
let res: StreamInfoConsumersReply = res;
let mut view: Vec<_> = res
.consumers
.iter()
.map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle))
.collect();
view.sort_by(|a, b| a.0.cmp(&b.0));
println!("{view:?}");
// >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)]
}
delete_keys(&mut r, &["race:italy"]);
let max1: Option<String> = r
.xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")])
.expect("maxlen add 1");
let max1 = max1.expect("missing stream id");
println!("{max1}"); // >>> 1-0
let max2: Option<String> = r
.xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")])
.expect("maxlen add 2");
let max2 = max2.expect("missing stream id");
println!("{max2}"); // >>> 2-0
let max3: Option<String> = r
.xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")])
.expect("maxlen add 3");
let max3 = max3.expect("missing stream id");
println!("{max3}"); // >>> 3-0
if let Ok(res) = r.xlen("race:italy") {
let res: usize = res;
println!("{res}"); // >>> 2
}
if let Ok(res) = r.xrange_all("race:italy") {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}");
// >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])]
}
delete_keys(&mut r, &["race:italy"]);
let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).expect("trim seed 1");
let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).expect("trim seed 2");
if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)) {
let res: usize = res;
println!("{res}"); // >>> 0
}
seed_trim_stream(&mut r);
if let Ok(res) = r.xtrim_options(
"mystream",
&StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10),
) {
let res: usize = res;
println!("{res}"); // >>> 0
}
delete_keys(&mut r, &["race:italy"]);
let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).expect("xdel seed 1");
let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).expect("xdel seed 2");
if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])]
}
if let Ok(res) = r.xdel("race:italy", &["3-0"]) {
let res: usize = res;
println!("{res}"); // >>> 1
}
if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2) {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])]
}
}
}
mod tests {
use redis::{
streams::{
StreamAutoClaimOptions, StreamInfoConsumersReply, StreamInfoGroupsReply,
StreamInfoStreamReply, StreamMaxlen, StreamPendingCountReply, StreamPendingReply,
StreamRangeReply, StreamReadOptions, StreamReadReply, StreamTrimmingMode, StreamTrimOptions,
},
AsyncCommands,
};
use tokio::time::{sleep, Duration};
async fn delete_keys(r: &mut redis::aio::MultiplexedConnection, keys: &[&str]) {
let _: usize = r.del(keys).await.unwrap_or(0);
}
async fn add_france_fixed(r: &mut redis::aio::MultiplexedConnection) {
delete_keys(r, &["race:france"]).await;
let _: Option<String> = r
.xadd(
"race:france",
"1692632086370-0",
&[
("rider", "Castilla"),
("speed", "30.2"),
("position", "1"),
("location_id", "1"),
],
)
.await
.expect("add france 1");
let _: Option<String> = r
.xadd(
"race:france",
"1692632094485-0",
&[
("rider", "Norem"),
("speed", "28.8"),
("position", "3"),
("location_id", "1"),
],
)
.await
.expect("add france 2");
let _: Option<String> = r
.xadd(
"race:france",
"1692632102976-0",
&[
("rider", "Prickett"),
("speed", "29.7"),
("position", "2"),
("location_id", "1"),
],
)
.await
.expect("add france 3");
let _: Option<String> = r
.xadd(
"race:france",
"1692632147973-0",
&[
("rider", "Castilla"),
("speed", "29.9"),
("position", "1"),
("location_id", "2"),
],
)
.await
.expect("add france 4");
}
async fn seed_usa_fixed(r: &mut redis::aio::MultiplexedConnection) {
delete_keys(r, &["race:usa"]).await;
let _: Option<String> = r
.xadd("race:usa", "0-1", &[("racer", "Castilla")])
.await
.expect("add usa 1");
let _: Option<String> = r
.xadd("race:usa", "0-2", &[("racer", "Norem")])
.await
.expect("add usa 2");
}
async fn seed_italy_group_base(r: &mut redis::aio::MultiplexedConnection) {
delete_keys(r, &["race:italy"]).await;
let _: () = r
.xgroup_create_mkstream("race:italy", "italy_riders", "$")
.await
.expect("create italy group");
let _: Option<String> = r
.xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")])
.await
.expect("add italy 1");
let _: Option<String> = r
.xadd("race:italy", "1692632647899-0", &[("rider", "Royce")])
.await
.expect("add italy 2");
let _: Option<String> = r
.xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")])
.await
.expect("add italy 3");
let _: Option<String> = r
.xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")])
.await
.expect("add italy 4");
let _: Option<String> = r
.xadd("race:italy", "1692632678249-0", &[("rider", "Norem")])
.await
.expect("add italy 5");
}
async fn seed_italy_alice_pending(r: &mut redis::aio::MultiplexedConnection) {
seed_italy_group_base(r).await;
let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1);
let _: Option<StreamReadReply> = r
.xread_options(&["race:italy"], &[">"], &opts)
.await
.expect("alice read pending");
}
async fn seed_italy_after_ack(r: &mut redis::aio::MultiplexedConnection) {
seed_italy_alice_pending(r).await;
let _: usize = r
.xack("race:italy", "italy_riders", &["1692632639151-0"])
.await
.expect("ack first italy message");
}
async fn seed_italy_bob_pending(r: &mut redis::aio::MultiplexedConnection) {
seed_italy_after_ack(r).await;
let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2);
let _: Option<StreamReadReply> = r
.xread_options(&["race:italy"], &[">"], &opts)
.await
.expect("bob read pending");
}
async fn seed_italy_info_state(r: &mut redis::aio::MultiplexedConnection) {
seed_italy_bob_pending(r).await;
sleep(Duration::from_millis(5)).await;
let _: redis::streams::StreamClaimReply = r
.xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"])
.await
.expect("alice claim");
sleep(Duration::from_millis(5)).await;
let _: redis::streams::StreamClaimReply = r
.xclaim("race:italy", "italy_riders", "Lora", 1, &["1692632662819-0"])
.await
.expect("lora claim");
}
async fn seed_trim_stream(r: &mut redis::aio::MultiplexedConnection) {
delete_keys(r, &["mystream"]).await;
for id in ["1-0", "2-0", "3-0", "4-0", "5-0", "6-0", "7-0", "8-0", "9-0", "10-0"] {
let _: Option<String> = r
.xadd("mystream", id, &[("field", "value")])
.await
.expect("seed mystream");
}
}
async fn run() {
let mut r = match redis::Client::open("redis://127.0.0.1") {
Ok(client) => match client.get_multiplexed_async_connection().await {
Ok(conn) => conn,
Err(e) => {
println!("Failed to connect to Redis: {e}");
return;
}
},
Err(e) => {
println!("Failed to create Redis client: {e}");
return;
}
};
let res1: Option<String> = r
.xadd(
"race:france",
"*",
&[
("rider", "Castilla"),
("speed", "30.2"),
("position", "1"),
("location_id", "1"),
],
)
.await
.expect("xadd 1");
let res1 = res1.expect("missing stream id");
println!("{res1}"); // >>> 1692632086370-0
let res2: Option<String> = r
.xadd(
"race:france",
"*",
&[
("rider", "Norem"),
("speed", "28.8"),
("position", "3"),
("location_id", "1"),
],
)
.await
.expect("xadd 2");
let res2 = res2.expect("missing stream id");
println!("{res2}"); // >>> 1692632094485-0
let res3: Option<String> = r
.xadd(
"race:france",
"*",
&[
("rider", "Prickett"),
("speed", "29.7"),
("position", "2"),
("location_id", "1"),
],
)
.await
.expect("xadd 3");
let res3 = res3.expect("missing stream id");
println!("{res3}"); // >>> 1692632102976-0
add_france_fixed(&mut r).await;
if let Ok(res) = r.xrange_count("race:france", "1692632086370-0", "+", 2).await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])]
}
add_france_fixed(&mut r).await;
let opts = StreamReadOptions::default().count(100).block(300);
if let Ok(res) = r.xread_options(&["race:france"], &["$"], &opts).await {
let res: Option<StreamReadReply> = res;
println!("{res:?}"); // >>> None
}
if let Ok(res) = r
.xadd(
"race:france",
"*",
&[
("rider", "Castilla"),
("speed", "29.9"),
("position", "1"),
("location_id", "2"),
],
)
.await
{
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 1692632147973-0
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xlen("race:france").await {
let res: usize = res;
println!("{res}"); // >>> 4
}
delete_keys(&mut r, &["race:usa"]).await;
if let Ok(res) = r.xadd("race:usa", "0-1", &[("racer", "Castilla")]).await {
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 0-1
}
if let Ok(res) = r.xadd("race:usa", "0-2", &[("racer", "Norem")]).await {
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 0-2
}
let res: redis::RedisResult<Option<String>> =
r.xadd("race:usa", "0-1", &[("racer", "Prickett")]).await;
match res {
Ok(_) => {}
Err(e) => {
let msg = e.to_string();
println!("{msg}");
// >>> An error was signalled by the server - ResponseError: The ID specified in XADD is equal or smaller than the target stream top item
}
}
seed_usa_fixed(&mut r).await;
if let Ok(res) = r.xadd("race:usa", "0-*", &[("racer", "Prickett")]).await {
let res: Option<String> = res;
let res = res.expect("missing stream id");
println!("{res}"); // >>> 0-3
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xrange_all("race:france").await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")]), ("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])]
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xrange("race:france", "1692632086369", "1692632086371").await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")])]
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xrange_count("race:france", "-", "+", 2).await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])]
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xrange_count("race:france", "(1692632094485-0", "+", 2).await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632102976-0", [("rider", "Prickett"), ("speed", "29.7"), ("position", "2"), ("location_id", "1")]), ("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])]
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xrange_count("race:france", "(1692632147973-0", "+", 2).await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}"); // >>> []
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xrevrange_count("race:france", "+", "-", 1).await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect();
println!("{view:?}");
// >>> [("1692632147973-0", [("rider", "Castilla"), ("speed", "29.9"), ("position", "1"), ("location_id", "2")])]
}
add_france_fixed(&mut r).await;
let opts = StreamReadOptions::default().count(2);
if let Ok(res) = r.xread_options(&["race:france"], &["0"], &opts).await {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("xread should return data")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![
("rider".to_string(), entry.get::<String>("rider").expect("missing rider")),
("speed".to_string(), entry.get::<String>("speed").expect("missing speed")),
("position".to_string(), entry.get::<String>("position").expect("missing position")),
(
"location_id".to_string(),
entry.get::<String>("location_id").expect("missing location_id"),
),
],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:france", [("1692632086370-0", [("rider", "Castilla"), ("speed", "30.2"), ("position", "1"), ("location_id", "1")]), ("1692632094485-0", [("rider", "Norem"), ("speed", "28.8"), ("position", "3"), ("location_id", "1")])])]
}
add_france_fixed(&mut r).await;
if let Ok(res) = r.xgroup_create("race:france", "france_riders", "$").await {
let res: () = res;
let _ = res;
println!("OK"); // >>> OK
}
delete_keys(&mut r, &["race:italy"]).await;
if let Ok(res) = r.xgroup_create_mkstream("race:italy", "italy_riders", "$").await {
let res: () = res;
let _ = res;
println!("OK"); // >>> OK
}
delete_keys(&mut r, &["race:italy"]).await;
let _: () = r
.xgroup_create_mkstream("race:italy", "italy_riders", "$")
.await
.expect("create italy group");
let italy_1: Option<String> = r
.xadd("race:italy", "1692632639151-0", &[("rider", "Castilla")])
.await
.expect("italy1");
let italy_1 = italy_1.expect("missing stream id");
println!("{italy_1}"); // >>> 1692632639151-0
let italy_2: Option<String> = r
.xadd("race:italy", "1692632647899-0", &[("rider", "Royce")])
.await
.expect("italy2");
let italy_2 = italy_2.expect("missing stream id");
println!("{italy_2}"); // >>> 1692632647899-0
let italy_3: Option<String> = r
.xadd("race:italy", "1692632662819-0", &[("rider", "Sam-Bodden")])
.await
.expect("italy3");
let italy_3 = italy_3.expect("missing stream id");
println!("{italy_3}"); // >>> 1692632662819-0
let italy_4: Option<String> = r
.xadd("race:italy", "1692632670501-0", &[("rider", "Prickett")])
.await
.expect("italy4");
let italy_4 = italy_4.expect("missing stream id");
println!("{italy_4}"); // >>> 1692632670501-0
let italy_5: Option<String> = r
.xadd("race:italy", "1692632678249-0", &[("rider", "Norem")])
.await
.expect("italy5");
let italy_5 = italy_5.expect("missing stream id");
println!("{italy_5}"); // >>> 1692632678249-0
let opts = StreamReadOptions::default().group("italy_riders", "Alice").count(1);
if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("xgroup read should return data")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])]
}
seed_italy_alice_pending(&mut r).await;
let opts = StreamReadOptions::default().group("italy_riders", "Alice");
if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("xgroup history")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:italy", [("1692632639151-0", [("rider", "Castilla")])])]
}
seed_italy_alice_pending(&mut r).await;
if let Ok(res) = r.xack("race:italy", "italy_riders", &["1692632639151-0"]).await {
let res: usize = res;
println!("{res}"); // >>> 1
}
let opts = StreamReadOptions::default().group("italy_riders", "Alice");
if let Ok(res) = r.xread_options(&["race:italy"], &["0"], &opts).await {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("xgroup history")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}"); // >>> [("race:italy", [])]
}
seed_italy_after_ack(&mut r).await;
let opts = StreamReadOptions::default().group("italy_riders", "Bob").count(2);
if let Ok(res) = r.xread_options(&["race:italy"], &[">"], &opts).await {
let res: Option<StreamReadReply> = res;
let view: Vec<_> = res
.expect("bob should receive data")
.keys
.iter()
.map(|stream| {
(
stream.key.clone(),
stream
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect::<Vec<_>>(),
)
})
.collect();
println!("{view:?}");
// >>> [("race:italy", [("1692632647899-0", [("rider", "Royce")]), ("1692632662819-0", [("rider", "Sam-Bodden")])])]
}
seed_italy_bob_pending(&mut r).await;
if let Ok(res) = r.xpending("race:italy", "italy_riders").await {
let res: StreamPendingReply = res;
let view = match res {
StreamPendingReply::Empty => None,
StreamPendingReply::Data(data) => Some((
data.count,
data.start_id.clone(),
data.end_id.clone(),
data.consumers
.iter()
.map(|consumer| (consumer.name.clone(), consumer.pending))
.collect::<Vec<_>>(),
)),
}
.expect("pending summary");
println!("{view:?}");
// >>> (2, "1692632647899-0", "1692632662819-0", [("Bob", 2)])
}
seed_italy_bob_pending(&mut r).await;
sleep(Duration::from_millis(5)).await;
if let Ok(res) = r.xpending_count("race:italy", "italy_riders", "-", "+", 10).await {
let res: StreamPendingCountReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
entry.consumer.clone(),
entry.last_delivered_ms,
entry.times_delivered,
)
})
.collect();
println!("{view:?}");
// >>> [("1692632647899-0", "Bob", 5, 1), ("1692632662819-0", "Bob", 5, 1)]
}
seed_italy_bob_pending(&mut r).await;
if let Ok(res) = r.xrange("race:italy", "1692632647899-0", "1692632647899-0").await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])]
}
seed_italy_bob_pending(&mut r).await;
sleep(Duration::from_millis(5)).await;
if let Ok(res) = r
.xclaim("race:italy", "italy_riders", "Alice", 1, &["1692632647899-0"])
.await
{
let res: redis::streams::StreamClaimReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("1692632647899-0", [("rider", "Royce")])]
}
seed_italy_bob_pending(&mut r).await;
sleep(Duration::from_millis(5)).await;
let opts = StreamAutoClaimOptions::default().count(1);
if let Ok(res) = r
.xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", opts)
.await
{
let res: redis::streams::StreamAutoClaimReply = res;
let claimed: Vec<_> = res
.claimed
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{:?}", (res.next_stream_id.clone(), &claimed));
// >>> ("1692632662819-0", [("1692632647899-0", [("rider", "Royce")])])
}
seed_italy_bob_pending(&mut r).await;
sleep(Duration::from_millis(5)).await;
let first_opts = StreamAutoClaimOptions::default().count(1);
let _: redis::streams::StreamAutoClaimReply = r
.xautoclaim_options("race:italy", "italy_riders", "Alice", 1, "0-0", first_opts)
.await
.expect("first autoclaim");
let next_opts = StreamAutoClaimOptions::default().count(1);
if let Ok(res) = r
.xautoclaim_options(
"race:italy",
"italy_riders",
"Lora",
1,
"(1692632647899-0",
next_opts,
)
.await
{
let res: redis::streams::StreamAutoClaimReply = res;
let claimed: Vec<_> = res
.claimed
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{:?}", (res.next_stream_id.clone(), &claimed));
// >>> ("0-0", [("1692632662819-0", [("rider", "Sam-Bodden")])])
}
seed_italy_info_state(&mut r).await;
if let Ok(res) = r.xinfo_stream("race:italy").await {
let res: StreamInfoStreamReply = res;
let view = (
res.length,
res.radix_tree_keys,
res.groups,
res.last_generated_id.clone(),
res.first_entry.id.clone(),
res.last_entry.id.clone(),
);
println!("{view:?}");
// >>> (5, 1, 1, "1692632678249-0", "1692632639151-0", "1692632678249-0")
}
seed_italy_info_state(&mut r).await;
if let Ok(res) = r.xinfo_groups("race:italy").await {
let res: StreamInfoGroupsReply = res;
let view: Vec<_> = res
.groups
.iter()
.map(|group| {
(
group.name.clone(),
group.consumers,
group.pending,
group.last_delivered_id.clone(),
)
})
.collect();
println!("{view:?}");
// >>> [("italy_riders", 3, 2, "1692632662819-0")]
}
seed_italy_info_state(&mut r).await;
if let Ok(res) = r.xinfo_consumers("race:italy", "italy_riders").await {
let res: StreamInfoConsumersReply = res;
let mut view: Vec<_> = res
.consumers
.iter()
.map(|consumer| (consumer.name.clone(), consumer.pending, consumer.idle))
.collect();
view.sort_by(|a, b| a.0.cmp(&b.0));
println!("{view:?}");
// >>> [("Alice", 1, 5), ("Bob", 0, 5), ("Lora", 1, 5)]
}
delete_keys(&mut r, &["race:italy"]).await;
let max1: Option<String> = r
.xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "1-0", &[("rider", "Jones")])
.await
.expect("maxlen add 1");
let max1 = max1.expect("missing stream id");
println!("{max1}"); // >>> 1-0
let max2: Option<String> = r
.xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "2-0", &[("rider", "Wood")])
.await
.expect("maxlen add 2");
let max2 = max2.expect("missing stream id");
println!("{max2}"); // >>> 2-0
let max3: Option<String> = r
.xadd_maxlen("race:italy", StreamMaxlen::Equals(2), "3-0", &[("rider", "Henshaw")])
.await
.expect("maxlen add 3");
let max3 = max3.expect("missing stream id");
println!("{max3}"); // >>> 3-0
if let Ok(res) = r.xlen("race:italy").await {
let res: usize = res;
println!("{res}"); // >>> 2
}
if let Ok(res) = r.xrange_all("race:italy").await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}");
// >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])]
}
delete_keys(&mut r, &["race:italy"]).await;
let _: Option<String> = r.xadd("race:italy", "1-0", &[("rider", "Wood")]).await.expect("trim seed 1");
let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Henshaw")]).await.expect("trim seed 2");
if let Ok(res) = r.xtrim("race:italy", StreamMaxlen::Equals(10)).await {
let res: usize = res;
println!("{res}"); // >>> 0
}
seed_trim_stream(&mut r).await;
if let Ok(res) = r
.xtrim_options(
"mystream",
&StreamTrimOptions::maxlen(StreamTrimmingMode::Approx, 10),
)
.await
{
let res: usize = res;
println!("{res}"); // >>> 0
}
delete_keys(&mut r, &["race:italy"]).await;
let _: Option<String> = r.xadd("race:italy", "2-0", &[("rider", "Wood")]).await.expect("xdel seed 1");
let _: Option<String> = r.xadd("race:italy", "3-0", &[("rider", "Henshaw")]).await.expect("xdel seed 2");
if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")]), ("3-0", [("rider", "Henshaw")])]
}
if let Ok(res) = r.xdel("race:italy", &["3-0"]).await {
let res: usize = res;
println!("{res}"); // >>> 1
}
if let Ok(res) = r.xrange_count("race:italy", "-", "+", 2).await {
let res: StreamRangeReply = res;
let view: Vec<_> = res
.ids
.iter()
.map(|entry| {
(
entry.id.clone(),
vec![(
"rider".to_string(),
entry.get::<String>("rider").expect("missing rider"),
)],
)
})
.collect();
println!("{view:?}"); // >>> [("2-0", [("rider", "Wood")])]
}
}
}
The above call to the XADD command adds an entry rider: Castilla, speed: 29.9, position: 1, location_id: 2 to the stream at key race:france, using an auto-generated entry ID, which is the one returned by the command, specifically 1692632147973-0. It gets as its first argument the key name race:france, the second argument is the entry ID that identifies every entry inside a stream. However, in this case, we passed * because we want the server to generate a new ID for us. Every new ID will be monotonically increasing, so in more simple terms, every new entry added will have a higher ID compared to all the past entries. Auto-generation of IDs by the server is almost always what you want, and the reasons for specifying an ID explicitly are very rare. We'll talk more about this later. The fact that each Stream entry has an ID is another similarity with log files, where line numbers, or the byte offset inside the file, can be used in order to identify a given entry. Returning back at our XADD example, after the key name and ID, the next arguments are the field-value pairs composing our stream entry.
It is possible to get the number of items inside a Stream just using the XLEN command:
> XLEN race:france
(integer) 4"""
Code samples for Stream doc pages:
https://redis.io/docs/latest/develop/data-types/streams/
"""
import redis
r = redis.Redis(decode_responses=True)
res1 = r.xadd(
"race:france",
{"rider": "Castilla", "speed": 30.2, "position": 1, "location_id": 1},
)
print(res1) # >>> 1692629576966-0
res2 = r.xadd(
"race:france",
{"rider": "Norem", "speed": 28.8, "position": 3, "location_id": 1},
)
print(res2) # >>> 1692629594113-0
res3 = r.xadd(
"race:france",
{"rider": "Prickett", "speed": 29.7, "position": 2, "location_id": 1},
)
print(res3) # >>> 1692629613374-0
res4 = r.xrange("race:france", "1691765278160-0", "+", 2)
print(
res4
) # >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# )
# ]
res5 = r.xread(streams={"race:france": 0}, count=100, block=300)
print(
res5
)
# >>> [
# ['race:france',
# [('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# ),
# ('1692629613374-0',
# {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}
# )]
# ]
# ]
res6 = r.xadd(
"race:france",
{"rider": "Castilla", "speed": 29.9, "position": 1, "location_id": 2},
)
print(res6) # >>> 1692629676124-0
res7 = r.xlen("race:france")
print(res7) # >>> 4
res8 = r.xadd("race:usa", {"racer": "Castilla"}, id="0-1")
print(res8) # >>> 0-1
res9 = r.xadd("race:usa", {"racer": "Norem"}, id="0-2")
print(res9) # >>> 0-2
try:
res10 = r.xadd("race:usa", {"racer": "Prickett"}, id="0-1")
print(res10) # >>> 0-1
except redis.exceptions.ResponseError as e:
print(e) # >>> WRONGID
# Not yet implemented
res11 = r.xrange("race:france", "-", "+")
print(
res11
)
# >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# ),
# ('1692629613374-0',
# {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}
# ),
# ('1692629676124-0',
# {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'}
# )
# ]
res12 = r.xrange("race:france", 1692629576965, 1692629576967)
print(
res12
)
# >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# )
# ]
res13 = r.xrange("race:france", "-", "+", 2)
print(
res13
)
# >>> [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# )
# ]
res14 = r.xrange("race:france", "(1692629594113-0", "+", 2)
print(
res14
)
# >>> [
# ('1692629613374-0',
# {'rider': 'Prickett', 'speed': '29.7', 'position': '2', 'location_id': '1'}
# ),
# ('1692629676124-0',
# {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'}
# )
# ]
res15 = r.xrange("race:france", "(1692629676124-0", "+", 2)
print(res15) # >>> []
res16 = r.xrevrange("race:france", "+", "-", 1)
print(
res16
)
# >>> [
# ('1692629676124-0',
# {'rider': 'Castilla', 'speed': '29.9', 'position': '1', 'location_id': '2'}
# )
# ]
res17 = r.xread(streams={"race:france": 0}, count=2)
print(
res17
)
# >>> [
# ['race:france', [
# ('1692629576966-0',
# {'rider': 'Castilla', 'speed': '30.2', 'position': '1', 'location_id': '1'}
# ),
# ('1692629594113-0',
# {'rider': 'Norem', 'speed': '28.8', 'position': '3', 'location_id': '1'}
# )
# ]
# ]
# ]
res18 = r.xgroup_create("race:france", "france_riders", "$")
print(res18) # >>> True
res19 = r.xgroup_create("race:italy", "italy_riders", "$", mkstream=True)
print(res19) # >>> True
r.xadd("race:italy", {"rider": "Castilla"})
r.xadd("race:italy", {"rider": "Royce"})
r.xadd("race:italy", {"rider": "Sam-Bodden"})
r.xadd("race:italy", {"rider": "Prickett"})
r.xadd("race:italy", {"rider": "Norem"})
res20 = r.xreadgroup(
streams={"race:italy": ">"},
consumername="Alice",
groupname="italy_riders",
count=1,
)
print(res20) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]]
res21 = r.xreadgroup(
streams={"race:italy": 0},
consumername="Alice",
groupname="italy_riders",
count=1,
)
print(res21) # >>> [['race:italy', [('1692629925771-0', {'rider': 'Castilla'})]]]
res22 = r.xack("race:italy", "italy_riders", "1692629925771-0")
print(res22) # >>> 1
res23 = r.xreadgroup(
streams={"race:italy": 0},
consumername="Alice",
groupname="italy_riders",
count=1,
)
print(res23) # >>> [['race:italy', []]]
res24 = r.xreadgroup(
streams={"race:italy": ">"},
consumername="Bob",
groupname="italy_riders",
count=2,
)
print(
res24
)
# >>> [
# ['race:italy', [
# ('1692629925789-0',
# {'rider': 'Royce'}
# ),
# ('1692629925790-0',
# {'rider': 'Sam-Bodden'}
# )
# ]
# ]
# ]
res25 = r.xpending("race:italy", "italy_riders")
print(
res25
)
# >>> {
# 'pending': 2, 'min': '1692629925789-0', 'max': '1692629925790-0',
# 'consumers': [{'name': 'Bob', 'pending': 2}]
# }
res26 = r.xpending_range("race:italy", "italy_riders", "-", "+", 10)
print(
res26
)
# >>> [
# {
# 'message_id': '1692629925789-0', 'consumer': 'Bob',
# 'time_since_delivered': 31084, 'times_delivered': 1
# },
# {
# 'message_id': '1692629925790-0', 'consumer': 'Bob',
# 'time_since_delivered': 31084, 'times_delivered': 1
# }
# ]
res27 = r.xrange("race:italy", "1692629925789-0", "1692629925789-0")
print(res27) # >>> [('1692629925789-0', {'rider': 'Royce'})]
res28 = r.xclaim("race:italy", "italy_riders", "Alice", 60000, ["1692629925789-0"])
print(res28) # >>> [('1692629925789-0', {'rider': 'Royce'})]
res29 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "0-0", 1)
print(res29) # >>> ['1692629925790-0', [('1692629925789-0', {'rider': 'Royce'})]]
res30 = r.xautoclaim("race:italy", "italy_riders", "Alice", 1, "(1692629925789-0", 1)
print(res30) # >>> ['0-0', [('1692629925790-0', {'rider': 'Sam-Bodden'})]]
res31 = r.xinfo_stream("race:italy")
print(
res31
)
# >>> {
# 'length': 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2,
# 'last-generated-id': '1692629926436-0', 'groups': 1,
# 'first-entry': ('1692629925771-0', {'rider': 'Castilla'}),
# 'last-entry': ('1692629926436-0', {'rider': 'Norem'})
# }
res32 = r.xinfo_groups("race:italy")
print(
res32
)
# >>> [
# {
# 'name': 'italy_riders', 'consumers': 2, 'pending': 2,
# 'last-delivered-id': '1692629925790-0'
# }
# ]
res33 = r.xinfo_consumers("race:italy", "italy_riders")
print(
res33
)
# >>> [
# {'name': 'Alice', 'pending': 2, 'idle': 199332},
# {'name': 'Bob', 'pending': 0, 'idle': 489170}
# ]
r.xadd("race:italy", {"rider": "Jones"}, maxlen=2)
r.xadd("race:italy", {"rider": "Wood"}, maxlen=2)
r.xadd("race:italy", {"rider": "Henshaw"}, maxlen=2)
res34 = r.xlen("race:italy")
print(res34) # >>> 8
res35 = r.xrange("race:italy", "-", "+")
print(
res35
)
# >>> [
# ('1692629925771-0', {'rider': 'Castilla'}),
# ('1692629925789-0', {'rider': 'Royce'}),
# ('1692629925790-0', {'rider': 'Sam-Bodden'}),
# ('1692629925791-0', {'rider': 'Prickett'}),
# ('1692629926436-0', {'rider': 'Norem'}),
# ('1692630612602-0', {'rider': 'Jones'}),
# ('1692630641947-0', {'rider': 'Wood'}),
# ('1692630648281-0', {'rider': 'Henshaw'})
# ]
r.xadd("race:italy", {"rider": "Smith"}, maxlen=2, approximate=False)
res36 = r.xrange("race:italy", "-", "+")
print(
res36
)
# >>> [
# ('1692630648281-0', {'rider': 'Henshaw'}),
# ('1692631018238-0', {'rider': 'Smith'})
# ]
res37 = r.xtrim("race:italy", maxlen=10, approximate=False)
print(res37) # >>> 0
res38 = r.xtrim("race:italy", maxlen=10)
print(res38) # >>> 0
res39 = r.xrange("race:italy", "-", "+")
print(
res39
)
# >>> [
# ('1692630648281-0', {'rider': 'Henshaw'}),
# ('1692631018238-0', {'rider': 'Smith'})
# ]
res40 = r.xdel("race:italy", "1692631018238-0")
print(res40) # >>> 1
res41 = r.xrange("race:italy", "-", "+")
print(res41) # >>> [('1692630648281-0', {'rider': 'Henshaw'})]
import assert from 'assert';
import {
createClient
} from 'redis';
const client = await createClient();
await client.connect();
const res1 = await client.xAdd(
'race:france', '*', {
'rider': 'Castilla',
'speed': '30.2',
'position': '1',
'location_id': '1'
}
);
console.log(res1); // >>> 1700073067968-0 N.B. actual values will differ from these examples
const res2 = await client.xAdd(
'race:france', '*', {
'rider': 'Norem',
'speed': '28.8',
'position': '3',
'location_id': '1'
},
);
console.log(res2); // >>> 1692629594113-0
const res3 = await client.xAdd(
'race:france', '*', {
'rider': 'Prickett',
'speed': '29.7',
'position': '2',
'location_id': '1'
},
);
console.log(res3); // >>> 1692629613374-0
const res4 = await client.xRange('race:france', '1691765278160-0', '+', {COUNT: 2});
console.log(res4); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }]
const res5 = await client.xRead({
key: 'race:france',
id: '0-0'
}, {
COUNT: 100,
BLOCK: 300
});
console.log(res5); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }] }]
const res6 = await client.xAdd(
'race:france', '*', {
'rider': 'Castilla',
'speed': '29.9',
'position': '1',
'location_id': '2'
}
);
console.log(res6); // >>> 1692629676124-0
const res7 = await client.xLen('race:france');
console.log(res7); // >>> 4
const res8 = await client.xAdd('race:usa', '0-1', {
'racer': 'Castilla'
});
console.log(res8); // >>> 0-1
const res9 = await client.xAdd('race:usa', '0-2', {
'racer': 'Norem'
});
console.log(res9); // >>> 0-2
try {
const res10 = await client.xAdd('race:usa', '0-1', {
'racer': 'Prickett'
});
console.log(res10); // >>> 0-1
} catch (error) {
console.error(error); // >>> [SimpleError: ERR The ID specified in XADD is equal or smaller than the target stream top item]
}
const res11a = await client.xAdd('race:usa', '0-*', { racer: 'Norem' });
console.log(res11a); // >>> 0-3
const res11 = await client.xRange('race:france', '-', '+');
console.log(res11); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }, { id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }]
const res12 = await client.xRange('race:france', '1692629576965', '1692629576967');
console.log(res12); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }]
const res13 = await client.xRange('race:france', '-', '+', {COUNT: 2});
console.log(res13); // >>> [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }]
const res14 = await client.xRange('race:france', '(1692629594113-0', '+', {COUNT: 2});
console.log(res14); // >>> [{ id: '1692629613374-0', message: { rider: 'Prickett', speed: '29.7', position: '2', location_id: '1' } }, { id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }]
const res15 = await client.xRange('race:france', '(1692629676124-0', '+', {COUNT: 2});
console.log(res15); // >>> []
const res16 = await client.xRevRange('race:france', '+', '-', {COUNT: 1});
console.log(
res16
); // >>> [{ id: '1692629676124-0', message: { rider: 'Castilla', speed: '29.9', position: '1', location_id: '2' } }]
const res17 = await client.xRead({
key: 'race:france',
id: '0-0'
}, {
COUNT: 2
});
console.log(res17); // >>> [{ name: 'race:france', messages: [{ id: '1692629576966-0', message: { rider: 'Castilla', speed: '30.2', position: '1', location_id: '1' } }, { id: '1692629594113-0', message: { rider: 'Norem', speed: '28.8', position: '3', location_id: '1' } }] }]
const res18 = await client.xGroupCreate('race:france', 'france_riders', '$');
console.log(res18); // >>> OK
const res19 = await client.xGroupCreate('race:italy', 'italy_riders', '$', {
MKSTREAM: true
});
console.log(res19); // >>> OK
await client.xAdd('race:italy', '*', {
'rider': 'Castilla'
});
await client.xAdd('race:italy', '*', {
'rider': 'Royce'
});
await client.xAdd('race:italy', '*', {
'rider': 'Sam-Bodden'
});
await client.xAdd('race:italy', '*', {
'rider': 'Prickett'
});
await client.xAdd('race:italy', '*', {
'rider': 'Norem'
});
const res20 = await client.xReadGroup(
'italy_riders',
'Alice', {
key: 'race:italy',
id: '>'
}, {
COUNT: 1
}
);
console.log(res20); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }]
const res21 = await client.xReadGroup(
'italy_riders',
'Alice', {
key: 'race:italy',
id: '0'
}, {
COUNT: 1
}
);
console.log(res21); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925771-0', message: { rider: 'Castilla' } }] }]
const res22 = await client.xAck('race:italy', 'italy_riders', '1692629925771-0')
console.log(res22); // >>> 1
const res23 = await client.xReadGroup(
'italy_riders',
'Alice', {
key: 'race:italy',
id: '0'
}, {
COUNT: 1
}
);
console.log(res23); // >>> [{ name: 'race:italy', messages: [] }]
const res24 = await client.xReadGroup(
'italy_riders',
'Bob', {
key: 'race:italy',
id: '>'
}, {
COUNT: 2
}
);
console.log(res24); // >>> [{ name: 'race:italy', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }, { id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }] }]
const res25 = await client.xPending('race:italy', 'italy_riders');
console.log(res25); // >>> {'pending': 2, 'firstId': '1692629925789-0', 'lastId': '1692629925790-0', 'consumers': [{'name': 'Bob', 'deliveriesCounter': 2}]}
const res26 = await client.xPendingRange('race:italy', 'italy_riders', '-', '+', 10);
console.log(res26); // >>> [{'id': '1692629925789-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter:': 1}, {'id': '1692629925790-0', 'consumer': 'Bob', 'millisecondsSinceLastDelivery': 31084, 'deliveriesCounter': 1}]
const res27 = await client.xRange('race:italy', '1692629925789-0', '1692629925789-0');
console.log(res27); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }]
const res28 = await client.xClaim(
'race:italy', 'italy_riders', 'Alice', 60000, ['1692629925789-0']
);
console.log(res28); // >>> [{ id: '1692629925789-0', message: { rider: 'Royce' } }]
const res29 = await client.xAutoClaim('race:italy', 'italy_riders', 'Alice', 1, '0-0', {
COUNT: 1
});
console.log(res29); // >>> { nextId: '1692629925790-0', messages: [{ id: '1692629925789-0', message: { rider: 'Royce' } }], deletedMessages: [] }
const res30 = await client.xAutoClaim(
'race:italy', 'italy_riders', 'Alice', 1, '(1692629925789-0',
{
COUNT: 1
}
);
console.log(res30); // >>> { nextId: '0-0', messages: [{ id: '1692629925790-0', message: { rider: 'Sam-Bodden' } }], deletedMessages: [] }
const res31 = await client.xInfoStream('race:italy');
console.log(res31); // >>> { length: 5, 'radix-tree-keys': 1, 'radix-tree-nodes': 2, 'last-generated-id': '1692629926436-0', 'max-deleted-entry-id': '0-0', 'entries-added': 5, 'recorded-first-entry-id': '1692629925771-0', groups: 1, 'first-entry': { id: '1692629925771-0', message: { rider: 'Castilla' } }, 'last-entry': { id: '1692629926436-0', message: { rider: 'Norem' } } }
const res32 = await client.xInfoGroups('race:italy');
console.log(res32); // >>> [{ name: 'italy_riders', consumers: 2, pending: 3, 'last-delivered-id': '1692629925790-0', 'entries-read': 3, lag: 2 }]
const res33 = await client.xInfoConsumers('race:italy', 'italy_riders');
console.log(res33); // >>> [{ name: 'Alice', pending: 3, idle: 170582, inactive: 170582 }, { name: 'Bob', pending: 0, idle: 489404, inactive: 489404 }]
await client.