Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
StackExchange.Redis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
StackExchange.Redis
Commits
9f326234
Commit
9f326234
authored
Mar 15, 2018
by
Daniel Chandler
Committed by
Nick Craver
Mar 14, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Transaction Conditions for Set Contains and Sorted Set Contains (#778)
parent
2bc189cc
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
169 additions
and
20 deletions
+169
-20
Transactions.cs
StackExchange.Redis.Tests/Transactions.cs
+84
-0
Condition.cs
StackExchange.Redis/StackExchange/Redis/Condition.cs
+85
-20
No files found.
StackExchange.Redis.Tests/Transactions.cs
View file @
9f326234
...
@@ -544,6 +544,48 @@ public void BasicTranWithSetCardinalityCondition(string value, ComparisonType ty
...
@@ -544,6 +544,48 @@ public void BasicTranWithSetCardinalityCondition(string value, ComparisonType ty
}
}
}
}
[
Theory
]
[
InlineData
(
false
,
false
,
true
)]
[
InlineData
(
false
,
true
,
false
)]
[
InlineData
(
true
,
false
,
false
)]
[
InlineData
(
true
,
true
,
true
)]
public
void
BasicTranWithSetContainsCondition
(
bool
demandKeyExists
,
bool
keyExists
,
bool
expectTranResult
)
{
using
(
var
muxer
=
Create
(
disabledCommands
:
new
[]
{
"info"
,
"config"
}))
{
RedisKey
key
=
Me
(),
key2
=
Me
()
+
"2"
;
var
db
=
muxer
.
GetDatabase
();
db
.
KeyDelete
(
key
,
CommandFlags
.
FireAndForget
);
db
.
KeyDelete
(
key2
,
CommandFlags
.
FireAndForget
);
RedisValue
member
=
"value"
;
if
(
keyExists
)
db
.
SetAdd
(
key2
,
member
,
flags
:
CommandFlags
.
FireAndForget
);
Assert
.
False
(
db
.
KeyExists
(
key
));
Assert
.
Equal
(
keyExists
,
db
.
SetContains
(
key2
,
member
));
var
tran
=
db
.
CreateTransaction
();
var
cond
=
tran
.
AddCondition
(
demandKeyExists
?
Condition
.
SetContains
(
key2
,
member
)
:
Condition
.
SetNotContains
(
key2
,
member
));
var
incr
=
tran
.
StringIncrementAsync
(
key
);
var
exec
=
tran
.
ExecuteAsync
();
var
get
=
db
.
StringGet
(
key
);
Assert
.
Equal
(
expectTranResult
,
db
.
Wait
(
exec
));
if
(
demandKeyExists
==
keyExists
)
{
Assert
.
True
(
db
.
Wait
(
exec
),
"eq: exec"
);
Assert
.
True
(
cond
.
WasSatisfied
,
"eq: was satisfied"
);
Assert
.
Equal
(
1
,
db
.
Wait
(
incr
));
// eq: incr
Assert
.
Equal
(
1
,
(
long
)
get
);
// eq: get
}
else
{
Assert
.
False
(
db
.
Wait
(
exec
),
"neq: exec"
);
Assert
.
False
(
cond
.
WasSatisfied
,
"neq: was satisfied"
);
Assert
.
Equal
(
TaskStatus
.
Canceled
,
incr
.
Status
);
// neq: incr
Assert
.
Equal
(
0
,
(
long
)
get
);
// neq: get
}
}
}
[
Theory
]
[
Theory
]
[
InlineData
(
"five"
,
ComparisonType
.
Equal
,
5L
,
false
)]
[
InlineData
(
"five"
,
ComparisonType
.
Equal
,
5L
,
false
)]
[
InlineData
(
"four"
,
ComparisonType
.
Equal
,
4L
,
true
)]
[
InlineData
(
"four"
,
ComparisonType
.
Equal
,
4L
,
true
)]
...
@@ -622,6 +664,48 @@ public void BasicTranWithSortedSetCardinalityCondition(string value, ComparisonT
...
@@ -622,6 +664,48 @@ public void BasicTranWithSortedSetCardinalityCondition(string value, ComparisonT
}
}
}
}
[
Theory
]
[
InlineData
(
false
,
false
,
true
)]
[
InlineData
(
false
,
true
,
false
)]
[
InlineData
(
true
,
false
,
false
)]
[
InlineData
(
true
,
true
,
true
)]
public
void
BasicTranWithSortedSetContainsCondition
(
bool
demandKeyExists
,
bool
keyExists
,
bool
expectTranResult
)
{
using
(
var
muxer
=
Create
(
disabledCommands
:
new
[]
{
"info"
,
"config"
}))
{
RedisKey
key
=
Me
(),
key2
=
Me
()
+
"2"
;
var
db
=
muxer
.
GetDatabase
();
db
.
KeyDelete
(
key
,
CommandFlags
.
FireAndForget
);
db
.
KeyDelete
(
key2
,
CommandFlags
.
FireAndForget
);
RedisValue
member
=
"value"
;
if
(
keyExists
)
db
.
SortedSetAdd
(
key2
,
member
,
0.0
,
flags
:
CommandFlags
.
FireAndForget
);
Assert
.
False
(
db
.
KeyExists
(
key
));
Assert
.
Equal
(
keyExists
,
db
.
SortedSetScore
(
key2
,
member
).
HasValue
);
var
tran
=
db
.
CreateTransaction
();
var
cond
=
tran
.
AddCondition
(
demandKeyExists
?
Condition
.
SortedSetContains
(
key2
,
member
)
:
Condition
.
SortedSetNotContains
(
key2
,
member
));
var
incr
=
tran
.
StringIncrementAsync
(
key
);
var
exec
=
tran
.
ExecuteAsync
();
var
get
=
db
.
StringGet
(
key
);
Assert
.
Equal
(
expectTranResult
,
db
.
Wait
(
exec
));
if
(
demandKeyExists
==
keyExists
)
{
Assert
.
True
(
db
.
Wait
(
exec
),
"eq: exec"
);
Assert
.
True
(
cond
.
WasSatisfied
,
"eq: was satisfied"
);
Assert
.
Equal
(
1
,
db
.
Wait
(
incr
));
// eq: incr
Assert
.
Equal
(
1
,
(
long
)
get
);
// eq: get
}
else
{
Assert
.
False
(
db
.
Wait
(
exec
),
"neq: exec"
);
Assert
.
False
(
cond
.
WasSatisfied
,
"neq: was satisfied"
);
Assert
.
Equal
(
TaskStatus
.
Canceled
,
incr
.
Status
);
// neq: incr
Assert
.
Equal
(
0
,
(
long
)
get
);
// neq: get
}
}
}
[
Theory
]
[
Theory
]
[
InlineData
(
"five"
,
ComparisonType
.
Equal
,
5L
,
false
)]
[
InlineData
(
"five"
,
ComparisonType
.
Equal
,
5L
,
false
)]
[
InlineData
(
"four"
,
ComparisonType
.
Equal
,
4L
,
true
)]
[
InlineData
(
"four"
,
ComparisonType
.
Equal
,
4L
,
true
)]
...
...
StackExchange.Redis/StackExchange/Redis/Condition.cs
View file @
9f326234
...
@@ -29,7 +29,7 @@ public static Condition HashEqual(RedisKey key, RedisValue hashField, RedisValue
...
@@ -29,7 +29,7 @@ public static Condition HashEqual(RedisKey key, RedisValue hashField, RedisValue
public
static
Condition
HashExists
(
RedisKey
key
,
RedisValue
hashField
)
public
static
Condition
HashExists
(
RedisKey
key
,
RedisValue
hashField
)
{
{
if
(
hashField
.
IsNull
)
throw
new
ArgumentNullException
(
nameof
(
hashField
));
if
(
hashField
.
IsNull
)
throw
new
ArgumentNullException
(
nameof
(
hashField
));
return
new
ExistsCondition
(
key
,
hashField
,
true
);
return
new
ExistsCondition
(
key
,
RedisType
.
Hash
,
hashField
,
true
);
}
}
/// <summary>
/// <summary>
...
@@ -48,7 +48,7 @@ public static Condition HashNotEqual(RedisKey key, RedisValue hashField, RedisVa
...
@@ -48,7 +48,7 @@ public static Condition HashNotEqual(RedisKey key, RedisValue hashField, RedisVa
public
static
Condition
HashNotExists
(
RedisKey
key
,
RedisValue
hashField
)
public
static
Condition
HashNotExists
(
RedisKey
key
,
RedisValue
hashField
)
{
{
if
(
hashField
.
IsNull
)
throw
new
ArgumentNullException
(
nameof
(
hashField
));
if
(
hashField
.
IsNull
)
throw
new
ArgumentNullException
(
nameof
(
hashField
));
return
new
ExistsCondition
(
key
,
hashField
,
false
);
return
new
ExistsCondition
(
key
,
RedisType
.
Hash
,
hashField
,
false
);
}
}
/// <summary>
/// <summary>
...
@@ -56,7 +56,7 @@ public static Condition HashNotExists(RedisKey key, RedisValue hashField)
...
@@ -56,7 +56,7 @@ public static Condition HashNotExists(RedisKey key, RedisValue hashField)
/// </summary>
/// </summary>
public
static
Condition
KeyExists
(
RedisKey
key
)
public
static
Condition
KeyExists
(
RedisKey
key
)
{
{
return
new
ExistsCondition
(
key
,
RedisValue
.
Null
,
true
);
return
new
ExistsCondition
(
key
,
Redis
Type
.
None
,
Redis
Value
.
Null
,
true
);
}
}
/// <summary>
/// <summary>
...
@@ -64,7 +64,7 @@ public static Condition KeyExists(RedisKey key)
...
@@ -64,7 +64,7 @@ public static Condition KeyExists(RedisKey key)
/// </summary>
/// </summary>
public
static
Condition
KeyNotExists
(
RedisKey
key
)
public
static
Condition
KeyNotExists
(
RedisKey
key
)
{
{
return
new
ExistsCondition
(
key
,
RedisValue
.
Null
,
false
);
return
new
ExistsCondition
(
key
,
Redis
Type
.
None
,
Redis
Value
.
Null
,
false
);
}
}
/// <summary>
/// <summary>
...
@@ -213,6 +213,22 @@ public static Condition SetLengthGreaterThan(RedisKey key, long length)
...
@@ -213,6 +213,22 @@ public static Condition SetLengthGreaterThan(RedisKey key, long length)
return
new
LengthCondition
(
key
,
RedisType
.
Set
,
-
1
,
length
);
return
new
LengthCondition
(
key
,
RedisType
.
Set
,
-
1
,
length
);
}
}
/// <summary>
/// Enforces that the given set contains a certain member
/// </summary>
public
static
Condition
SetContains
(
RedisKey
key
,
RedisValue
member
)
{
return
new
ExistsCondition
(
key
,
RedisType
.
Set
,
member
,
true
);
}
/// <summary>
/// Enforces that the given set does not contain a certain member
/// </summary>
public
static
Condition
SetNotContains
(
RedisKey
key
,
RedisValue
member
)
{
return
new
ExistsCondition
(
key
,
RedisType
.
Set
,
member
,
false
);
}
/// <summary>
/// <summary>
/// Enforces that the given sorted set cardinality is a certain value
/// Enforces that the given sorted set cardinality is a certain value
/// </summary>
/// </summary>
...
@@ -237,6 +253,22 @@ public static Condition SortedSetLengthGreaterThan(RedisKey key, long length)
...
@@ -237,6 +253,22 @@ public static Condition SortedSetLengthGreaterThan(RedisKey key, long length)
return
new
LengthCondition
(
key
,
RedisType
.
SortedSet
,
-
1
,
length
);
return
new
LengthCondition
(
key
,
RedisType
.
SortedSet
,
-
1
,
length
);
}
}
/// <summary>
/// Enforces that the given sorted set contains a certain member
/// </summary>
public
static
Condition
SortedSetContains
(
RedisKey
key
,
RedisValue
member
)
{
return
new
ExistsCondition
(
key
,
RedisType
.
SortedSet
,
member
,
true
);
}
/// <summary>
/// Enforces that the given sorted set does not contain a certain member
/// </summary>
public
static
Condition
SortedSetNotContains
(
RedisKey
key
,
RedisValue
member
)
{
return
new
ExistsCondition
(
key
,
RedisType
.
SortedSet
,
member
,
false
);
}
internal
abstract
void
CheckCommands
(
CommandMap
commandMap
);
internal
abstract
void
CheckCommands
(
CommandMap
commandMap
);
internal
abstract
IEnumerable
<
Message
>
CreateMessages
(
int
db
,
ResultBox
resultBox
);
internal
abstract
IEnumerable
<
Message
>
CreateMessages
(
int
db
,
ResultBox
resultBox
);
...
@@ -298,38 +330,62 @@ internal override void WriteImpl(PhysicalConnection physical)
...
@@ -298,38 +330,62 @@ internal override void WriteImpl(PhysicalConnection physical)
internal
class
ExistsCondition
:
Condition
internal
class
ExistsCondition
:
Condition
{
{
private
readonly
bool
expectedResult
;
private
readonly
bool
expectedResult
;
private
readonly
RedisValue
hashField
;
private
readonly
RedisValue
expectedValue
;
private
readonly
RedisKey
key
;
private
readonly
RedisKey
key
;
private
readonly
RedisType
type
;
private
readonly
RedisCommand
cmd
;
internal
override
Condition
MapKeys
(
Func
<
RedisKey
,
RedisKey
>
map
)
internal
override
Condition
MapKeys
(
Func
<
RedisKey
,
RedisKey
>
map
)
{
{
return
new
ExistsCondition
(
map
(
key
),
hashField
,
expectedResult
);
return
new
ExistsCondition
(
map
(
key
),
type
,
expectedValue
,
expectedResult
);
}
}
public
ExistsCondition
(
RedisKey
key
,
Redis
Value
hashField
,
bool
expectedResult
)
public
ExistsCondition
(
RedisKey
key
,
Redis
Type
type
,
RedisValue
expectedValue
,
bool
expectedResult
)
{
{
if
(
key
.
IsNull
)
throw
new
ArgumentException
(
"key"
);
if
(
key
.
IsNull
)
throw
new
ArgumentException
(
"key"
);
this
.
key
=
key
;
this
.
key
=
key
;
this
.
hashField
=
hashField
;
this
.
type
=
type
;
this
.
expectedValue
=
expectedValue
;
this
.
expectedResult
=
expectedResult
;
this
.
expectedResult
=
expectedResult
;
if
(
expectedValue
.
IsNull
)
{
cmd
=
RedisCommand
.
EXISTS
;
}
else
{
switch
(
type
)
{
case
RedisType
.
Hash
:
cmd
=
RedisCommand
.
HEXISTS
;
break
;
case
RedisType
.
Set
:
cmd
=
RedisCommand
.
SISMEMBER
;
break
;
case
RedisType
.
SortedSet
:
cmd
=
RedisCommand
.
ZSCORE
;
break
;
default
:
throw
new
ArgumentException
(
nameof
(
type
));
}
}
}
}
public
override
string
ToString
()
public
override
string
ToString
()
{
{
return
(
hashField
.
IsNull
?
key
.
ToString
()
:
((
string
)
key
)
+
" > "
+
hashField
)
return
(
expectedValue
.
IsNull
?
key
.
ToString
()
:
((
string
)
key
)
+
" "
+
type
+
" > "
+
expectedValue
)
+
(
expectedResult
?
" exists"
:
" does not exists"
);
+
(
expectedResult
?
" exists"
:
" does not exists"
);
}
}
internal
override
void
CheckCommands
(
CommandMap
commandMap
)
internal
override
void
CheckCommands
(
CommandMap
commandMap
)
{
{
commandMap
.
AssertAvailable
(
hashField
.
IsNull
?
RedisCommand
.
EXISTS
:
RedisCommand
.
HEXISTS
);
commandMap
.
AssertAvailable
(
cmd
);
}
}
internal
override
IEnumerable
<
Message
>
CreateMessages
(
int
db
,
ResultBox
resultBox
)
internal
override
IEnumerable
<
Message
>
CreateMessages
(
int
db
,
ResultBox
resultBox
)
{
{
yield
return
Message
.
Create
(
db
,
CommandFlags
.
None
,
RedisCommand
.
WATCH
,
key
);
yield
return
Message
.
Create
(
db
,
CommandFlags
.
None
,
RedisCommand
.
WATCH
,
key
);
var
cmd
=
hashField
.
IsNull
?
RedisCommand
.
EXISTS
:
RedisCommand
.
HEXISTS
;
var
message
=
ConditionProcessor
.
CreateMessage
(
this
,
db
,
CommandFlags
.
None
,
cmd
,
key
,
expectedValue
);
var
message
=
ConditionProcessor
.
CreateMessage
(
this
,
db
,
CommandFlags
.
None
,
cmd
,
key
,
hashField
);
message
.
SetSource
(
ConditionProcessor
.
Default
,
resultBox
);
message
.
SetSource
(
ConditionProcessor
.
Default
,
resultBox
);
yield
return
message
;
yield
return
message
;
}
}
...
@@ -340,15 +396,24 @@ internal override int GetHashSlot(ServerSelectionStrategy serverSelectionStrateg
...
@@ -340,15 +396,24 @@ internal override int GetHashSlot(ServerSelectionStrategy serverSelectionStrateg
}
}
internal
override
bool
TryValidate
(
RawResult
result
,
out
bool
value
)
internal
override
bool
TryValidate
(
RawResult
result
,
out
bool
value
)
{
{
bool
parsed
;
switch
(
type
)
{
if
(
ResultProcessor
.
DemandZeroOrOneProcessor
.
TryGet
(
result
,
out
parsed
))
case
RedisType
.
SortedSet
:
{
var
parsedValue
=
result
.
AsRedisValue
();
value
=
parsed
==
expectedResult
;
value
=
(
parsedValue
.
IsNull
!=
expectedResult
);
ConnectionMultiplexer
.
TraceWithoutContext
(
"exists: "
+
parsed
+
"; expected: "
+
expectedResult
+
"; voting: "
+
value
);
ConnectionMultiplexer
.
TraceWithoutContext
(
"exists: "
+
parsedValue
+
"; expected: "
+
expectedResult
+
"; voting: "
+
value
);
return
true
;
return
true
;
default
:
bool
parsed
;
if
(
ResultProcessor
.
DemandZeroOrOneProcessor
.
TryGet
(
result
,
out
parsed
))
{
value
=
parsed
==
expectedResult
;
ConnectionMultiplexer
.
TraceWithoutContext
(
"exists: "
+
parsed
+
"; expected: "
+
expectedResult
+
"; voting: "
+
value
);
return
true
;
}
value
=
false
;
return
false
;
}
}
value
=
false
;
return
false
;
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment