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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/Streams.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ You also have the option to override the auto-generated message ID by passing yo
db.StreamAdd("events_stream", "foo_name", "bar_value", messageId: "0-1", maxLength: 100);
```

Trimming, the entry ID and the other `XADD` options can be supplied together via `StreamAddOptions`:

```csharp
// append only if the stream already exists, trimming anything older than the given entry ID
var id = db.StreamAdd("events_stream", "foo_name", "bar_value", new StreamAddOptions
{
CreateStream = false, // NOMKSTREAM
MinId = "1526919030474-55", // or MaxLength, for MAXLEN
Approximate = true, // the "~" form, which is cheaper
});
```

With `CreateStream = false`, adding to a stream that does not exist returns `RedisValue.Null` and the key is
not created. `MinId` and `Approximate` require server version 6.2 or above.

Idempotent write-at-most-once production
===

Expand Down
35 changes: 35 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2835,6 +2835,41 @@ IEnumerable<SortedSetEntry> SortedSetScan(
/// <returns>The ID of the newly created message.</returns>
/// <remarks><seealso href="https://redis.io/commands/xadd"/></remarks>
RedisValue StreamAdd(RedisKey key, NameValueEntry[] streamPairs, StreamIdempotentId idempotentId, long? maxLength = null, bool useApproximateMaxLength = false, long? limit = null, StreamTrimMode trimMode = StreamTrimMode.KeepReferences, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Adds an entry using the specified values to the given stream key.
/// If key does not exist and <see cref="StreamAddOptions.CreateStream"/> is set, a new key holding a
/// stream is created. The command returns the ID of the newly created stream entry.
/// </summary>
/// <param name="key">The key of the stream.</param>
/// <param name="streamField">The field name for the stream entry.</param>
/// <param name="streamValue">The value to set in the stream entry.</param>
/// <param name="options">Additional options for this operation, such as trimming and the entry ID.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>
/// The ID of the newly created message, or a null value when the key does not exist and
/// <see cref="StreamAddOptions.CreateStream"/> is <c>false</c>.
/// </returns>
/// <remarks><seealso href="https://redis.io/commands/xadd"/></remarks>
#pragma warning disable RS0027 // additive overload: `options` is required, so existing calls still bind to the overloads above
RedisValue StreamAdd(RedisKey key, RedisValue streamField, RedisValue streamValue, StreamAddOptions options, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Adds an entry using the specified values to the given stream key.
/// If key does not exist and <see cref="StreamAddOptions.CreateStream"/> is set, a new key holding a
/// stream is created. The command returns the ID of the newly created stream entry.
/// </summary>
/// <param name="key">The key of the stream.</param>
/// <param name="streamPairs">The fields and their associated values to set in the stream entry.</param>
/// <param name="options">Additional options for this operation, such as trimming and the entry ID.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>
/// The ID of the newly created message, or a null value when the key does not exist and
/// <see cref="StreamAddOptions.CreateStream"/> is <c>false</c>.
/// </returns>
/// <remarks><seealso href="https://redis.io/commands/xadd"/></remarks>
RedisValue StreamAdd(RedisKey key, NameValueEntry[] streamPairs, StreamAddOptions options, CommandFlags flags = CommandFlags.None);
#pragma warning restore RS0027
#pragma warning restore RS0026

/// <summary>
Expand Down
8 changes: 8 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,14 @@ IAsyncEnumerable<SortedSetEntry> SortedSetScanAsync(

/// <inheritdoc cref="IDatabase.StreamAdd(RedisKey, NameValueEntry[], StreamIdempotentId, long?, bool, long?, StreamTrimMode, CommandFlags)"/>
Task<RedisValue> StreamAddAsync(RedisKey key, NameValueEntry[] streamPairs, StreamIdempotentId idempotentId, long? maxLength = null, bool useApproximateMaxLength = false, long? limit = null, StreamTrimMode trimMode = StreamTrimMode.KeepReferences, CommandFlags flags = CommandFlags.None);

/// <inheritdoc cref="IDatabase.StreamAdd(RedisKey, RedisValue, RedisValue, StreamAddOptions, CommandFlags)"/>
#pragma warning disable RS0027 // additive overload: `options` is required, so existing calls still bind to the overloads above
Task<RedisValue> StreamAddAsync(RedisKey key, RedisValue streamField, RedisValue streamValue, StreamAddOptions options, CommandFlags flags = CommandFlags.None);

/// <inheritdoc cref="IDatabase.StreamAdd(RedisKey, NameValueEntry[], StreamAddOptions, CommandFlags)"/>
Task<RedisValue> StreamAddAsync(RedisKey key, NameValueEntry[] streamPairs, StreamAddOptions options, CommandFlags flags = CommandFlags.None);
#pragma warning restore RS0027
#pragma warning restore RS0026

/// <inheritdoc cref="IDatabase.StreamConfigure(RedisKey, StreamConfiguration, CommandFlags)"/>
Expand Down
6 changes: 6 additions & 0 deletions src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,12 @@ public Task<RedisValue> StreamAddAsync(RedisKey key, RedisValue streamField, Red
public Task<RedisValue> StreamAddAsync(RedisKey key, NameValueEntry[] streamPairs, StreamIdempotentId idempotentId, long? maxLength = null, bool useApproximateMaxLength = false, long? limit = null, StreamTrimMode mode = StreamTrimMode.KeepReferences, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAddAsync(ToInner(key), streamPairs, idempotentId, maxLength, useApproximateMaxLength, limit, mode, flags);

public Task<RedisValue> StreamAddAsync(RedisKey key, RedisValue streamField, RedisValue streamValue, StreamAddOptions options, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAddAsync(ToInner(key), streamField, streamValue, options, flags);

public Task<RedisValue> StreamAddAsync(RedisKey key, NameValueEntry[] streamPairs, StreamAddOptions options, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAddAsync(ToInner(key), streamPairs, options, flags);

public Task StreamConfigureAsync(RedisKey key, StreamConfiguration configuration, CommandFlags flags = CommandFlags.None) =>
Inner.StreamConfigureAsync(ToInner(key), configuration, flags);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,12 @@ public RedisValue StreamAdd(RedisKey key, RedisValue streamField, RedisValue str
public RedisValue StreamAdd(RedisKey key, NameValueEntry[] streamPairs, StreamIdempotentId idempotentId, long? maxLength = null, bool useApproximateMaxLength = false, long? limit = null, StreamTrimMode mode = StreamTrimMode.KeepReferences, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAdd(ToInner(key), streamPairs, idempotentId, maxLength, useApproximateMaxLength, limit, mode, flags);

public RedisValue StreamAdd(RedisKey key, RedisValue streamField, RedisValue streamValue, StreamAddOptions options, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAdd(ToInner(key), streamField, streamValue, options, flags);

public RedisValue StreamAdd(RedisKey key, NameValueEntry[] streamPairs, StreamAddOptions options, CommandFlags flags = CommandFlags.None) =>
Inner.StreamAdd(ToInner(key), streamPairs, options, flags);

public void StreamConfigure(RedisKey key, StreamConfiguration configuration, CommandFlags flags = CommandFlags.None) =>
Inner.StreamConfigure(ToInner(key), configuration, flags);

Expand Down
22 changes: 22 additions & 0 deletions src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,25 @@ StackExchange.Redis.IServer.ClusterSlots(StackExchange.Redis.CommandFlags flags
StackExchange.Redis.IServer.ClusterSlotsAsync(StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.ClusterSlotsResult?>!
[SER007]StackExchange.Redis.RedisErrorKind.UnknownRedirectTarget = 26 -> StackExchange.Redis.RedisErrorKind
override StackExchange.Redis.ClusterSlotNode.ToString() -> string!
StackExchange.Redis.IDatabaseAsync.StreamAddAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.NameValueEntry[]! streamPairs, StackExchange.Redis.StreamAddOptions options, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.RedisValue>!
StackExchange.Redis.IDatabaseAsync.StreamAddAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue streamField, StackExchange.Redis.RedisValue streamValue, StackExchange.Redis.StreamAddOptions options, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.RedisValue>!
StackExchange.Redis.IDatabase.StreamAdd(StackExchange.Redis.RedisKey key, StackExchange.Redis.NameValueEntry[]! streamPairs, StackExchange.Redis.StreamAddOptions options, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue
StackExchange.Redis.IDatabase.StreamAdd(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue streamField, StackExchange.Redis.RedisValue streamValue, StackExchange.Redis.StreamAddOptions options, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue
StackExchange.Redis.StreamAddOptions
StackExchange.Redis.StreamAddOptions.Approximate.get -> bool
StackExchange.Redis.StreamAddOptions.Approximate.init -> void
StackExchange.Redis.StreamAddOptions.CreateStream.get -> bool
StackExchange.Redis.StreamAddOptions.CreateStream.init -> void
StackExchange.Redis.StreamAddOptions.IdempotentId.get -> StackExchange.Redis.StreamIdempotentId
StackExchange.Redis.StreamAddOptions.IdempotentId.init -> void
StackExchange.Redis.StreamAddOptions.Limit.get -> long?
StackExchange.Redis.StreamAddOptions.Limit.init -> void
StackExchange.Redis.StreamAddOptions.MaxLength.get -> long?
StackExchange.Redis.StreamAddOptions.MaxLength.init -> void
StackExchange.Redis.StreamAddOptions.MessageId.get -> StackExchange.Redis.RedisValue?
StackExchange.Redis.StreamAddOptions.MessageId.init -> void
StackExchange.Redis.StreamAddOptions.MinId.get -> StackExchange.Redis.RedisValue
StackExchange.Redis.StreamAddOptions.MinId.init -> void
StackExchange.Redis.StreamAddOptions.StreamAddOptions() -> void
StackExchange.Redis.StreamAddOptions.TrimMode.get -> StackExchange.Redis.StreamTrimMode
StackExchange.Redis.StreamAddOptions.TrimMode.init -> void
Loading
Loading