Commit 0ecb3c1e authored by Nathan Harris's avatar Nathan Harris

Iterate on type safety for `zadd`

Motivation:

Issue #60 called for improving the type safety of the options available for the `zadd` command, and MR !70 made some great headway, but attempted to cram too much into a single enum.

Modifications:

- Break the `RedisSortedSetAddOption.returnChangedCount` value into an additional boolean param

Result:

Using `zadd` should now be more straight forward, while being type safe.
parent 26057638
Pipeline #70031001 passed with stages
in 9 minutes and 49 seconds
......@@ -47,45 +47,43 @@ extension RedisClient {
// MARK: General
/// The supported options for the `zadd` command with Redis SortedSet types.
/// - Important: Per Redis documentation, `.onlyUpdateExistingElements` and `.onlyAddNewElements` are mutually exclusive!
/// - Note: `INCR` is not supported by this library in `zadd`. Use the `zincrby(:element:in:)` method instead.
///
/// See [https://redis.io/commands/zadd#zadd-options-redis-302-or-greater](https://redis.io/commands/zadd#zadd-options-redis-302-or-greater)
public enum RedisSortedSetAddOption: String {
/// When adding elements, any that do not already exist in the SortedSet will be ignored and the score of the existing element will be updated.
case onlyUpdateExistingElements = "XX"
/// When adding elements, any that already exist in the SortedSet will be ignored and the score of the existing element will not be updated.
case onlyAddNewElements = "NX"
/// `zadd` normally returns the number of new elements added to the set,
/// but this option will instead have the command return the number of elements changed.
///
/// "Changed" in this context are new elements added, and elements that had their score updated.
case returnChangedCount = "CH"
}
extension RedisClient {
/// Adds elements to a sorted set, assigning their score to the values provided.
/// - Note: `INCR` is not supported by this library in `zadd`. Use the `zincrby(:element:in:)` method instead.
///
/// See [https://redis.io/commands/zadd](https://redis.io/commands/zadd)
/// - Parameters:
/// - elements: A list of elements and their score to add to the sorted set.
/// - key: The key of the sorted set.
/// - options: A set of options defined by Redis for this command to execute under.
/// - Returns: The number of elements added to the sorted set.
/// - option: An option for modifying the behavior of the command.
/// - returnChangedCount: `zadd` normally returns the number of new elements added to the set,
/// but setting this to `true` will instead have the command return the number of elements changed.
///
/// "Changed" in this context are new elements added, and elements that had their score updated.
/// - Returns: The number of elements added to the sorted set, unless `returnChangedCount` was set to `true`.
@inlinable
public func zadd<Value: RESPValueConvertible>(
_ elements: [(element: Value, score: Double)],
to key: String,
options: Set<RedisSortedSetAddOption> = []
option: RedisSortedSetAddOption? = nil,
returnChangedCount: Bool = false
) -> EventLoopFuture<Int> {
assert(options.count <= 2, "Invalid number of options provided.")
assert(
!(options.contains(.onlyAddNewElements) && options.contains(.onlyUpdateExistingElements)),
".onlyAddNewElements and .onlyUpdateExistingElements options are mutually exclusive."
)
var args: [RESPValue] = [.init(bulk: key)]
args.add(contentsOf: options) { (array, option) in
array.append(.init(bulk: option.rawValue))
if let opt = option {
args.append(.init(bulk: opt.rawValue))
}
if returnChangedCount {
args.append(.init(bulk: "CH"))
}
args.add(contentsOf: elements, overestimatedCountBeingAdded: elements.count * 2) { (array, next) in
array.append(.init(bulk: next.score.description))
......@@ -102,15 +100,20 @@ extension RedisClient {
/// - Parameters:
/// - element: The element and its score to add to the sorted set.
/// - key: The key of the sorted set.
/// - options: A set of options defined by Redis for this command to execute under.
/// - Returns: `true` if the element was added or score was updated in the sorted set.
/// - option: An option for modifying the behavior of the command.
/// - returnChangedCount: `zadd` normally returns the number of new elements added to the set,
/// but setting this to `true` will instead have the command return the number of elements changed.
///
/// "Changed" in this context are new elements added, and elements that had their score updated.
/// - Returns: `true` if the element was added or score was updated in the sorted set, depending on the `option` and `returnChangedCount` settings set.
@inlinable
public func zadd<Value: RESPValueConvertible>(
_ element: (element: Value, score: Double),
to key: String,
options: Set<RedisSortedSetAddOption> = []
option: RedisSortedSetAddOption? = nil,
returnChangedCount: Bool = false
) -> EventLoopFuture<Bool> {
return zadd([element], to: key, options: options)
return zadd([element], to: key, option: option, returnChangedCount: returnChangedCount)
.map { return $0 == 1 }
}
......
......@@ -43,18 +43,19 @@ final class SortedSetCommandsTests: RedisIntegrationTestCase {
XCTAssertEqual(count, 1)
count = try connection.zadd([(30, 5)], to: #function).wait()
XCTAssertEqual(count, 0)
count = try connection.zadd([(30, 6), (31, 0), (32, 1)], to: #function, options: [.onlyAddNewElements]).wait()
count = try connection.zadd([(30, 6), (31, 0), (32, 1)], to: #function, option: .onlyAddNewElements).wait()
XCTAssertEqual(count, 2)
count = try connection.zadd(
[(32, 2), (33, 3)],
to: #function,
options: [.onlyUpdateExistingElements, .returnChangedCount]
option: .onlyUpdateExistingElements,
returnChangedCount: true
).wait()
XCTAssertEqual(count, 1)
var success = try connection.zadd((30, 7), to: #function, options: [.returnChangedCount]).wait()
var success = try connection.zadd((30, 7), to: #function, returnChangedCount: true).wait()
XCTAssertTrue(success)
success = try connection.zadd((30, 8), to: #function, options: [.onlyAddNewElements]).wait()
success = try connection.zadd((30, 8), to: #function, option: .onlyAddNewElements).wait()
XCTAssertFalse(success)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment