Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
4
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
RediStack
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
18
Issues
18
List
Boards
Labels
Service Desk
Milestones
Iterations
Merge Requests
3
Merge Requests
3
Requirements
Requirements
List
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Test Cases
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Code Review
Insights
Issue
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nathan Harris
RediStack
Commits
f4e646c1
Commit
f4e646c1
authored
Mar 23, 2019
by
Nathan Harris
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Audit convenience commands
Motivation: Performance, clarity, and uniformity with code documentation, Swift API, and data types.
parent
601431ac
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
919 additions
and
579 deletions
+919
-579
Sources/NIORedis/Commands/BasicCommands.swift
Sources/NIORedis/Commands/BasicCommands.swift
+55
-142
Sources/NIORedis/Commands/HashCommands.swift
Sources/NIORedis/Commands/HashCommands.swift
+197
-121
Sources/NIORedis/Commands/ListCommands.swift
Sources/NIORedis/Commands/ListCommands.swift
+120
-59
Sources/NIORedis/Commands/SetCommands.swift
Sources/NIORedis/Commands/SetCommands.swift
+182
-88
Sources/NIORedis/Commands/SortedSetCommands.swift
Sources/NIORedis/Commands/SortedSetCommands.swift
+203
-169
Sources/NIORedis/Commands/StringCommands.swift
Sources/NIORedis/Commands/StringCommands.swift
+162
-0
No files found.
Sources/NIORedis/Commands/BasicCommands.swift
View file @
f4e646c1
...
...
@@ -7,6 +7,7 @@ extension RedisCommandExecutor {
/// See [https://redis.io/commands/echo](https://redis.io/commands/echo)
/// - Parameter message: The message to echo.
/// - Returns: The message sent with the command.
@inlinable
public
func
echo
(
_
message
:
String
)
->
EventLoopFuture
<
String
>
{
return
send
(
command
:
"ECHO"
,
with
:
[
message
])
.
mapFromRESP
()
...
...
@@ -15,8 +16,9 @@ extension RedisCommandExecutor {
/// Pings the server, which will respond with a message.
///
/// See [https://redis.io/commands/ping](https://redis.io/commands/ping)
/// - Parameter
with
: The optional message that the server should respond with.
/// - Parameter
message
: The optional message that the server should respond with.
/// - Returns: The provided message or Redis' default response of `"PONG"`.
@inlinable
public
func
ping
(
with
message
:
String
?
=
nil
)
->
EventLoopFuture
<
String
>
{
let
arg
=
message
!=
nil
?
[
message
]
:
[]
return
send
(
command
:
"PING"
,
with
:
arg
)
...
...
@@ -26,196 +28,102 @@ extension RedisCommandExecutor {
/// Request for authentication in a password-protected Redis server.
///
/// [https://redis.io/commands/auth](https://redis.io/commands/auth)
/// - Parameter password: The password being used to access the Redis server.
/// - Returns: An `EventLoopFuture` that resolves when the connection has been authorized, or fails with a `RedisError`.
@inlinable
public
func
authorize
(
with
password
:
String
)
->
EventLoopFuture
<
Void
>
{
return
send
(
command
:
"AUTH"
,
with
:
[
password
])
.
map
{
_
in
return
()
}
}
/// Select the Redis logical database having the specified zero-based numeric index.
/// New connections always use the database `0`.
///
- Note:
New connections always use the database `0`.
///
/// [https://redis.io/commands/select](https://redis.io/commands/select)
public
func
select
(
database
id
:
Int
)
->
EventLoopFuture
<
Void
>
{
return
send
(
command
:
"SELECT"
,
with
:
[
id
.
description
])
/// - Parameter index: The 0-based index of the database that will receive later commands.
/// - Returns: An `EventLoopFuture` that resolves when the operation has succeeded, or fails with a `RedisError`.
@inlinable
public
func
select
(
database
index
:
Int
)
->
EventLoopFuture
<
Void
>
{
return
send
(
command
:
"SELECT"
,
with
:
[
index
])
.
map
{
_
in
return
()
}
}
/// Swaps the data of two Redis database
by their index ID
.
/// Swaps the data of two Redis database
s by their index IDs
.
///
/// See [https://redis.io/commands/swapdb](https://redis.io/commands/swapdb)
/// - Parameters:
/// - first
Index
: The index of the first database.
/// - second
Index
: The index of the second database.
/// - first: The index of the first database.
/// - second: The index of the second database.
/// - Returns: `true` if the swap was successful.
public
func
swapdb
(
firstIndex
:
Int
,
secondIndex
:
Int
)
->
EventLoopFuture
<
Bool
>
{
return
send
(
command
:
"SWAPDB"
,
with
:
[
firstIndex
,
secondIndex
])
@inlinable
public
func
swapDatabase
(
_
first
:
Int
,
with
second
:
Int
)
->
EventLoopFuture
<
Bool
>
{
/// connection.swapDatabase(index: 0, withIndex: 10)
return
send
(
command
:
"SWAPDB"
,
with
:
[
first
,
second
])
.
mapFromRESP
(
to
:
String
.
self
)
.
map
{
return
$0
==
"OK"
}
}
}
extension
RedisCommandExecutor
{
/// Removes the specified keys. A key is ignored if it does not exist.
///
/// [https://redis.io/commands/del](https://redis.io/commands/del)
/// - Returns: A future number of keys that were removed.
public
func
delete
(
_
keys
:
String
...
)
->
EventLoopFuture
<
Int
>
{
/// - Parameter keys: A list of keys to delete from the database.
/// - Returns: The number of keys deleted from the database.
@inlinable
public
func
delete
(
_
keys
:
[
String
])
->
EventLoopFuture
<
Int
>
{
guard
keys
.
count
>
0
else
{
return
self
.
eventLoop
.
makeSucceededFuture
(
0
)
}
return
send
(
command
:
"DEL"
,
with
:
keys
)
.
mapFromRESP
()
}
/// Set a timeout on key. After the timeout has expired, the key will automatically be deleted.
///
A key with an associated timeout is often said to be volatile
in Redis terminology.
/// Set
s
a timeout on key. After the timeout has expired, the key will automatically be deleted.
///
- Note: A key with an associated timeout is often said to be "volatile"
in Redis terminology.
///
/// [https://redis.io/commands/expire](https://redis.io/commands/expire)
/// - Parameters:
/// - after: The lifetime (in seconds) the key will expirate at.
/// - Returns: A future bool indicating if the expiration was set or not.
public
func
expire
(
_
key
:
String
,
after
deadline
:
Int
)
->
EventLoopFuture
<
Bool
>
{
return
send
(
command
:
"EXPIRE"
,
with
:
[
key
,
deadline
.
description
])
.
mapFromRESP
(
to
:
Int
.
self
)
.
map
{
return
$0
==
1
}
}
/// Get the value of a key.
/// If the key does not exist the value will be `nil`.
/// An error is resolved if the value stored at key is not a string, because GET only handles string values.
///
/// [https://redis.io/commands/get](https://redis.io/commands/get)
public
func
get
(
_
key
:
String
)
->
EventLoopFuture
<
String
?
>
{
return
send
(
command
:
"GET"
,
with
:
[
key
])
.
map
{
return
$0
.
string
}
}
/// Returns the values of all specified keys, using `.null` to represent non-existant values.
///
/// See [https://redis.io/commands/mget](https://redis.io/commands/mget)
public
func
mget
(
_
keys
:
[
String
])
->
EventLoopFuture
<
[
RESPValue
]
>
{
assert
(
keys
.
count
>
0
,
"At least 1 key should be provided."
)
return
send
(
command
:
"MGET"
,
with
:
keys
)
.
mapFromRESP
()
}
/// Set key to hold the string value.
/// If key already holds a value, it is overwritten, regardless of its type.
/// Any previous time to live associated with the key is discarded on successful SET operation.
///
/// [https://redis.io/commands/set](https://redis.io/commands/set)
public
func
set
(
_
key
:
String
,
to
value
:
String
)
->
EventLoopFuture
<
Void
>
{
return
send
(
command
:
"SET"
,
with
:
[
key
,
value
])
.
map
{
_
in
return
()
}
}
/// Sets each key to the respective new value, overwriting existing values.
///
/// - Note: Use `msetnx` if you don't want to overwrite values.
///
/// See [https://redis.io/commands/mset](https://redis.io/commands/mset)
public
func
mset
(
_
operations
:
[
String
:
RESPValueConvertible
])
->
EventLoopFuture
<
Void
>
{
assert
(
operations
.
count
>
0
,
"At least 1 key-value pair should be provided."
)
let
args
=
_convertMSET
(
operations
)
return
send
(
command
:
"MSET"
,
with
:
args
)
.
map
{
_
in
return
()
}
}
/// If every key does not exist, sets each key to the respective new value.
///
/// See [https://redis.io/commands/msetnx](https://redis.io/commands/msetnx)
public
func
msetnx
(
_
operations
:
[
String
:
RESPValueConvertible
])
->
EventLoopFuture
<
Bool
>
{
assert
(
operations
.
count
>
0
,
"At least 1 key-value pair should be provided."
)
let
args
=
_convertMSET
(
operations
)
return
send
(
command
:
"MSETNX"
,
with
:
args
)
/// - key: The key to set the expiration on.
/// - deadline: The time from now the key will expire at.
/// - Returns: `true` if the expiration was set.
@inlinable
public
func
expire
(
_
key
:
String
,
after
deadline
:
TimeAmount
)
->
EventLoopFuture
<
Bool
>
{
let
amount
=
deadline
.
nanoseconds
/
1_000_000_000
return
send
(
command
:
"EXPIRE"
,
with
:
[
key
,
amount
])
.
mapFromRESP
(
to
:
Int
.
self
)
.
map
{
return
$0
==
1
}
}
@inline
(
__always
)
private
func
_convertMSET
(
_
source
:
[
String
:
RESPValueConvertible
])
->
[
RESPValueConvertible
]
{
return
source
.
reduce
(
into
:
[
RESPValueConvertible
](),
{
(
result
,
element
)
in
result
.
append
(
element
.
key
)
result
.
append
(
element
.
value
)
})
}
}
extension
RedisCommandExecutor
{
/// Increments the stored value by 1 and returns the new value.
///
/// See [https://redis.io/commands/incr](https://redis.io/commands/incr)
/// - Returns: The new value after the operation.
public
func
increment
(
_
key
:
String
)
->
EventLoopFuture
<
Int
>
{
return
send
(
command
:
"INCR"
,
with
:
[
key
])
.
mapFromRESP
()
}
/// Increments the stored value by the amount desired and returns the new value.
///
/// See [https://redis.io/commands/incrby](https://redis.io/commands/incrby)
/// - Returns: The new value after the operation.
public
func
increment
(
_
key
:
String
,
by
count
:
Int
)
->
EventLoopFuture
<
Int
>
{
return
send
(
command
:
"INCRBY"
,
with
:
[
key
,
count
])
.
mapFromRESP
()
}
/// Increments the stored value by the amount desired and returns the new value.
///
/// See [https://redis.io/commands/incrbyfloat](https://redis.io/commands/incrbyfloat)
/// - Returns: The new value after the operation.
public
func
increment
<
T
:
BinaryFloatingPoint
>
(
_
key
:
String
,
by
count
:
T
)
->
EventLoopFuture
<
T
>
where
T
:
RESPValueConvertible
{
return
send
(
command
:
"INCRBYFLOAT"
,
with
:
[
key
,
count
])
.
mapFromRESP
()
}
/// Decrements the stored value by 1 and returns the new value.
///
/// See [https://redis.io/commands/decr](https://redis.io/commands/decr)
/// - Returns: The new value after the operation.
public
func
decrement
(
_
key
:
String
)
->
EventLoopFuture
<
Int
>
{
return
send
(
command
:
"DECR"
,
with
:
[
key
])
.
mapFromRESP
()
}
/// Decrements the stored valye by the amount desired and returns the new value.
///
/// See [https://redis.io/commands/decrby](https://redis.io/commands/decrby)
/// - Returns: The new value after the operation.
public
func
decrement
(
_
key
:
String
,
by
count
:
Int
)
->
EventLoopFuture
<
Int
>
{
return
send
(
command
:
"DECRBY"
,
with
:
[
key
,
count
])
.
mapFromRESP
()
}
}
// MARK: Scan
extension
RedisCommandExecutor
{
/// Incrementally iterates over all keys in the currently selected database.
///
/// [https://redis.io/commands/scan](https://redis.io/commands/scan)
/// - Parameters:
/// -
startingFrom
: The cursor position to start from.
/// -
position
: The cursor position to start from.
/// - count: The number of elements to advance by. Redis default is 10.
/// - match
ing
: A glob-style pattern to filter values to be selected from the result set.
/// - Returns: A cursor position for additional invocations with a limited collection of keys
store
d in the database.
/// - match: A glob-style pattern to filter values to be selected from the result set.
/// - Returns: A cursor position for additional invocations with a limited collection of keys
foun
d in the database.
@inlinable
public
func
scan
(
startingFrom
pos
:
Int
=
0
,
startingFrom
pos
ition
:
Int
=
0
,
count
:
Int
?
=
nil
,
matching
match
:
String
?
=
nil
)
->
EventLoopFuture
<
(
Int
,
[
String
])
>
{
return
_scan
(
command
:
"SCAN"
,
resultType
:
[
String
]
.
self
,
nil
,
pos
,
count
,
match
)
matching
match
:
String
?
=
nil
)
->
EventLoopFuture
<
(
Int
,
[
String
])
>
{
return
_scan
(
command
:
"SCAN"
,
nil
,
position
,
count
,
match
)
}
@
inline
(
__always
)
@usableFromInline
func
_scan
<
T
:
RESPValueConvertible
>
(
@
usableFromInline
func
_scan
<
T
>
(
command
:
String
,
resultType
:
T
.
Type
,
resultType
:
T
.
Type
=
T
.
self
,
_
key
:
String
?,
_
pos
:
Int
,
_
count
:
Int
?,
_
match
:
String
?)
->
EventLoopFuture
<
(
Int
,
T
)
>
_
match
:
String
?
)
->
EventLoopFuture
<
(
Int
,
T
)
>
where
T
:
RESPValueConvertible
{
var
args
:
[
RESPValueConvertible
]
=
[
pos
]
...
...
@@ -237,7 +145,12 @@ extension RedisCommandExecutor {
guard
let
value
=
result
[
0
]
.
string
,
let
position
=
Int
(
value
)
else
{
throw
RedisError
(
identifier
:
#function
,
reason
:
"Unexpected value in response:
\(
result
[
0
]
)
"
)
}
else
{
throw
RedisError
(
identifier
:
#function
,
reason
:
"Unexpected value in response:
\(
result
[
0
]
)
"
)
}
return
position
}
let
elements
=
response
...
...
Sources/NIORedis/Commands/HashCommands.swift
View file @
f4e646c1
import
NIO
extension
RedisCommandExecutor
{
/// Sets the hash field stored at the provided key with the value specified.
///
/// See [https://redis.io/commands/hset](https://redis.io/commands/hset)
/// - Returns: `true` if the hash was created, `false` if it was updated.
@inlinable
public
func
hset
(
_
key
:
String
,
field
:
String
,
to
value
:
String
)
->
EventLoopFuture
<
Bool
>
{
return
send
(
command
:
"HSET"
,
with
:
[
key
,
field
,
value
])
.
mapFromRESP
(
to
:
Int
.
self
)
.
map
{
return
$0
==
1
}
}
/// Sets the specified fields to the values provided, overwriting existing values.
///
/// See [https://redis.io/commands/hmset](https://redis.io/commands/hmset)
@inlinable
public
func
hmset
(
_
key
:
String
,
to
fields
:
[
String
:
String
])
->
EventLoopFuture
<
Void
>
{
assert
(
fields
.
count
>
0
,
"At least 1 key-value pair should be specified"
)
let
args
:
[
RESPValueConvertible
]
=
fields
.
reduce
(
into
:
[],
{
(
result
,
element
)
in
result
.
append
(
element
.
key
)
result
.
append
(
element
.
value
)
})
return
send
(
command
:
"HMSET"
,
with
:
[
key
]
+
args
)
.
map
{
_
in
()
}
}
// MARK: Static Helpers
/// Sets the specified hash field to the value provided only if the field does not exist.
///
/// See [https://redis.io/commands/hsetnx](https://redis.io/commands/hsetnx)
/// - Returns: The success of setting the field's value.
@inlinable
public
func
hsetnx
(
_
key
:
String
,
field
:
String
,
to
value
:
String
)
->
EventLoopFuture
<
Bool
>
{
return
send
(
command
:
"HSETNX"
,
with
:
[
key
,
field
,
value
])
.
mapFromRESP
(
to
:
Int
.
self
)
.
map
{
return
$0
==
1
}
}
extension
RedisCommandExecutor
{
@usableFromInline
static
func
_mapHashResponse
(
_
values
:
[
String
])
->
[
String
:
String
]
{
guard
values
.
count
>
0
else
{
return
[:]
}
/// Gets the value stored in the hash field at the key provided.
///
/// See [https://redis.io/commands/hget](https://redis.io/commands/hget)
@inlinable
public
func
hget
(
_
key
:
String
,
field
:
String
)
->
EventLoopFuture
<
String
?
>
{
return
send
(
command
:
"HGET"
,
with
:
[
key
,
field
])
.
map
{
return
String
(
$0
)
}
}
var
result
:
[
String
:
String
]
=
[:]
/// Returns the values stored in the fields specified at the key provided.
///
/// See [https://redis.io/commands/hmget](https://redis.io/commands/hmget)
/// - Returns: A list of values in the same order as the `fields` argument.
@inlinabl
e
public
func
hmget
(
_
key
:
String
,
fields
:
[
String
])
->
EventLoopFuture
<
[
String
?]
>
{
assert
(
fields
.
count
>
0
,
"At least 1 field should be specified"
)
var
index
=
0
repeat
{
let
field
=
values
[
index
]
let
value
=
values
[
index
+
1
]
result
[
field
]
=
valu
e
index
+=
2
}
while
(
index
<
values
.
count
)
return
send
(
command
:
"HMGET"
,
with
:
[
key
]
+
fields
)
.
mapFromRESP
(
to
:
[
RESPValue
]
.
self
)
.
map
{
return
$0
.
map
(
String
.
init
)
}
return
result
}
}
/// Returns all the fields and values stored at the provided key.
///
/// See [https://redis.io/commands/hgetall](https://redis.io/commands/hgetall)
/// - Returns: A key-value pair list of fields and their values.
@inlinable
public
func
hgetall
(
from
key
:
String
)
->
EventLoopFuture
<
[
String
:
String
]
>
{
return
send
(
command
:
"HGETALL"
,
with
:
[
key
])
.
mapFromRESP
(
to
:
[
String
]
.
self
)
.
map
(
Self
.
mapHashResponseToDictionary
)
}
// MARK: General
/// Removes the specified fields from the hash stored at the key provided.
extension
RedisCommandExecutor
{
/// Removes the specified fields from a hash.
///
/// See [https://redis.io/commands/hdel](https://redis.io/commands/hdel)
/// - Parameters:
/// - fields: The list of field names that should be removed from the hash.
/// - key: The key of the hash to delete from.
/// - Returns: The number of fields that were deleted.
@inlinable
public
func
hdel
(
_
key
:
String
,
fields
:
[
String
]
)
->
EventLoopFuture
<
Int
>
{
assert
(
fields
.
count
>
0
,
"At least 1 field should be specified"
)
public
func
hdel
(
_
fields
:
[
String
],
from
key
:
String
)
->
EventLoopFuture
<
Int
>
{
guard
fields
.
count
>
0
else
{
return
self
.
eventLoop
.
makeSucceededFuture
(
0
)
}
return
send
(
command
:
"HDEL"
,
with
:
[
key
]
+
fields
)
.
mapFromRESP
()
}
/// Checks if
the provided key and field exist
.
/// Checks if
a hash contains the field specified
.
///
/// See [https://redis.io/commands/hexists](https://redis.io/commands/hexists)
/// - Parameters:
/// - field: The field name to look for.
/// - key: The key of the hash to look within.
/// - Returns: `true` if the hash contains the field, `false` if either the key or field do not exist.
@inlinable
public
func
hexists
(
_
key
:
String
,
field
:
String
)
->
EventLoopFuture
<
Bool
>
{
public
func
hexists
(
_
field
:
String
,
in
key
:
String
)
->
EventLoopFuture
<
Bool
>
{
return
send
(
command
:
"HEXISTS"
,
with
:
[
key
,
field
])
.
mapFromRESP
(
to
:
Int
.
self
)
.
map
{
return
$0
==
1
}
}
///
Returns the number of fields contained in the hash stored at the key provided
.
///
Gets the number of fields contained in a hash
.
///
/// See [https://redis.io/commands/hlen](https://redis.io/commands/hlen)
/// - Returns: The number of fields in the hash, or 0 if the key doesn't exist.
/// - Parameter key: The key of the hash to get field count of.
/// - Returns: The number of fields in the hash, or `0` if the key doesn't exist.
@inlinable
public
func
hlen
(
of
key
:
String
)
->
EventLoopFuture
<
Int
>
{
return
send
(
command
:
"HLEN"
,
with
:
[
key
])
.
mapFromRESP
()
}
///
Returns hash field's value length as a string, stored at the provided key
.
///
Gets the string length of a hash field's value
.
///
/// See [https://redis.io/commands/hstrlen](https://redis.io/commands/hstrlen)
/// - Parameters:
/// - field: The field name whose value is being accessed.
/// - key: The key of the hash.
/// - Returns: The string length of the hash field's value, or `0` if the field or hash do not exist.
@inlinable
public
func
hstrlen
(
of
key
:
String
,
field
:
String
)
->
EventLoopFuture
<
Int
>
{
public
func
hstrlen
(
of
field
:
String
,
in
key
:
String
)
->
EventLoopFuture
<
Int
>
{
return
send
(
command
:
"HSTRLEN"
,
with
:
[
key
,
field
])
.
mapFromRESP
()
}
///
Returns all field names in the hash stored at the key provided
.
///
Gets all field names in a hash
.
///
/// See [https://redis.io/commands/hkeys](https://redis.io/commands/hkeys)
/// - Returns: An array of field names, or an empty array.
/// - Parameter key: The key of the hash.
/// - Returns: A list of field names stored within the hash.
@inlinable
public
func
hkeys
(
storedAt
key
:
String
)
->
EventLoopFuture
<
[
String
]
>
{
public
func
hkeys
(
in
key
:
String
)
->
EventLoopFuture
<
[
String
]
>
{
return
send
(
command
:
"HKEYS"
,
with
:
[
key
])
.
mapFromRESP
()
}
///
Returns all of the field values stored in hash at the key provided
.
///
Gets all values stored in a hash
.
///
/// See [https://redis.io/commands/hvals](https://redis.io/commands/hvals)
/// - Parameter key: The key of the hash.
/// - Returns: A list of all values stored in a hash.
@inlinable
public
func
hvals
(
storedAt
key
:
String
)
->
EventLoopFuture
<
[
String
]
>
{
public
func
hvals
(
in
key
:
String
)
->
EventLoopFuture
<
[
RESPValue
]
>
{
return
send
(
command
:
"HVALS"
,
with
:
[
key
])
.
mapFromRESP
()
}
/// Increments the field value stored at the key provided, and returns the new value.
///
/// See [https://redis.io/commands/hincrby](https://redis.io/commands/hincrby)
@inlinable
public
func
hincrby
(
_
key
:
String
,
field
:
String
,
by
amount
:
Int
)
->
EventLoopFuture
<
Int
>
{
return
send
(
command
:
"HINCRBY"
,
with
:
[
key
,
field
,
amount
])
.
mapFromRESP
()
}
/// Increments the field value stored at the key provided, and returns the new value.
///
/// See [https://redis.io/commands/hincrbyfloat](https://redis.io/commands/hincrbyfloat)
@inlinable
public
func
hincrbyfloat
<
T
:
BinaryFloatingPoint
>
(
_
key
:
String
,
field
:
String
,
by
amount
:
T
)
->
EventLoopFuture
<
T
>
where
T
:
RESPValueConvertible
{
return
send
(
command
:
"HINCRBYFLOAT"
,
with
:
[
key
,
field
,
amount
])
.
mapFromRESP
()
}
/// Incrementally iterates over all fields in the hash stored at the key provided.
/// Incrementally iterates over all fields in a hash.
///
/// [https://redis.io/commands/scan](https://redis.io/commands/scan)
/// - Parameters:
/// - key: The key of the hash.
/// -
atP
osition: The position to start the scan from.
/// -
p
osition: The position to start the scan from.
/// - count: The number of elements to advance by. Redis default is 10.
/// - match
ing
: A glob-style pattern to filter values to be selected from the result set.
/// - Returns: A cursor position for additional invocations with a limited collection of
values stored at the key
s.
/// - match: A glob-style pattern to filter values to be selected from the result set.
/// - Returns: A cursor position for additional invocations with a limited collection of
found fields and their value
s.
@inlinable
public
func
hscan
(
_
key
:
String
,
atPosition
pos
:
Int
=
0
,
startingFrom
position
:
Int
=
0
,
count
:
Int
?
=
nil
,
matching
match
:
String
?
=
nil
)
->
EventLoopFuture
<
(
Int
,
[
String
:
String
])
>
{
return
_scan
(
command
:
"HSCAN"
,
resultType
:
[
String
]
.
self
,
key
,
pos
,
count
,
match
)
matching
match
:
String
?
=
nil
)
->
EventLoopFuture
<
(
Int
,
[
String
:
String
])
>
{
return
_scan
(
command
:
"HSCAN"
,
resultType
:
[
String
]
.
self
,
key
,
pos
ition
,
count
,
match
)
.
map
{
let
values
=
Self
.
mapHashResponseToDictionary
(
$0
.
1
)
let
values
=
Self
.
_mapHashResponse
(
$0
.
1
)
return
(
$0
.
0
,
values
)
}
}
}
// MARK: Set
extension
RedisCommandExecutor
{
@inline
(
__always
)
@usableFromInline
static
func
mapHashResponseToDictionary
(
_
values
:
[
String
])
->
[
String
:
String
]
{
guard
values
.
count
>
0
else
{
return
[:]
}
/// Sets a hash field to the value specified.
/// - Note: If you do not want to overwrite existing values, use `hsetnx(_:field:to:)`.
///
/// See [https://redis.io/commands/hset](https://redis.io/commands/hset)
/// - Parameters:
/// - field: The name of the field in the hash being set.
/// - value: The value the hash field should be set to.
/// - key: The key that holds the hash.
/// - Returns: `true` if the hash was created, `false` if it was updated.
@inlinable
public
func
hset
(
_
field
:
String
,
to
value
:
RESPValueConvertible
,
in
key
:
String
)
->
EventLoopFuture
<
Bool
>
{
return
send
(
command
:
"HSET"
,
with
:
[
key
,
field
,
value
])
.
mapFromRESP
(
to
:
Int
.
self
)
.
map
{
return
$0
==
1
}
}
var
result
:
[
String
:
String
]
=
[:]
/// Sets a hash field to the value specified only if the field does not currently exist.
/// - Note: If you do not care about overwriting existing values, use `hset(_:field:to:)`.
///
/// See [https://redis.io/commands/hsetnx](https://redis.io/commands/hsetnx)
/// - Parameters:
/// - field: The name of the field in the hash being set.
/// - value: The value the hash field should be set to.
/// - key: The key that holds the hash.
/// - Returns: `true` if the hash was created.
@inlinable
public
func
hsetnx
(
_
field
:
String
,
to
value
:
RESPValueConvertible
,
in
key
:
String
)
->
EventLoopFuture
<
Bool
>
{
return
send
(
command
:
"HSETNX"
,
with
:
[
key
,
field
,
value
])
.
mapFromRESP
(
to
:
Int
.
self
)
.
map
{
return
$0
==
1
}
}
var
index
=
0
repeat
{
let
field
=
values
[
index
]
let
value
=
values
[
index
+
1
]
result
[
field
]
=
value
index
+=
2
}
while
(
index
<
values
.
count
)
/// Sets the fields in a hash to the respective values provided.
///
/// See [https://redis.io/commands/hmset](https://redis.io/commands/hmset)
/// - Parameters:
/// - fields: The key-value pair of field names and their respective values to set.
/// - key: The key that holds the hash.
/// - Returns: An `EventLoopFuture` that resolves when the operation has succeeded, or fails with a `RedisError`.
@inlinable
public
func
hmset
(
_
fields
:
[
String
:
RESPValueConvertible
],
in
key
:
String
)
->
EventLoopFuture
<
Void
>
{
assert
(
fields
.
count
>
0
,
"At least 1 key-value pair should be specified"
)
return
result