Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve 'SET' command #803

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object ContributorsCache {
ZIO
.fromOption(NonEmptyChunk.fromChunk(contributors))
.map(Contributors(_).toJson)
.flatMap(data => redis.set(repository.key, data, expireAt = Some(SetExpire.SetExpireSeconds(1.minute))).orDie)
.flatMap(data => redis.set(repository.key, data, expireAt = Some(SetExpire.Seconds(60))).orDie)
.ignore

private def read(repository: Repository): IO[ApiError, Contributors] =
Expand Down
30 changes: 15 additions & 15 deletions modules/redis-it/src/test/scala/zio/redis/StringsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1507,23 +1507,23 @@ trait StringsSpec extends IntegrationSpec {
redis <- ZIO.service[Redis]
key <- uuid
value <- uuid
result <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireSeconds(1.second)))
result <- redis.set(key, value, expireAt = Some(SetExpire.Seconds(1)))
} yield assert(result)(isTrue)
},
test("new value with ttl 100 milliseconds") {
for {
redis <- ZIO.service[Redis]
key <- uuid
value <- uuid
result <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireMilliseconds(100.milliseconds)))
result <- redis.set(key, value, expireAt = Some(SetExpire.Milliseconds(100)))
} yield assert(result)(isTrue)
},
test("error when negative ttl") {
for {
redis <- ZIO.service[Redis]
key <- uuid
value <- uuid
result <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireMilliseconds((-1).millisecond))).either
result <- redis.set(key, value, expireAt = Some(SetExpire.Milliseconds(-1))).either
} yield assert(result)(isLeft(isSubtype[ProtocolError](anything)))
},
test("new value with SetNew parameter") {
Expand Down Expand Up @@ -1583,7 +1583,7 @@ trait StringsSpec extends IntegrationSpec {
redis <- ZIO.service[Redis]
key <- uuid
value <- uuid
_ <- redis.set(key, "value", expireAt = Some(SetExpire.SetExpireSeconds(1.second)))
_ <- redis.set(key, "value", expireAt = Some(SetExpire.Seconds(1)))
result <- redis.set(key, value, expireAt = Some(SetExpire.KeepTtl))
} yield assert(result)(isTrue)
}
Expand Down Expand Up @@ -1635,7 +1635,7 @@ trait StringsSpec extends IntegrationSpec {
redis <- ZIO.service[Redis]
key <- uuid
value <- uuid
_ <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireSeconds(1.second)))
_ <- redis.set(key, value, expireAt = Some(SetExpire.Seconds(1)))
existsBefore <- redis.exists(key)
fiber <- ZIO.sleep(1010.millis).fork <* TestClock.adjust(1010.millis)
_ <- fiber.join
Expand All @@ -1648,7 +1648,7 @@ trait StringsSpec extends IntegrationSpec {
key <- uuid
value <- uuid
_ <- redis.set(key, "value")
_ <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireSeconds(1.second)))
_ <- redis.set(key, value, expireAt = Some(SetExpire.Seconds(1)))
existsBefore <- redis.exists(key)
fiber <- ZIO.sleep(1010.millis).fork <* TestClock.adjust(1010.millis)
_ <- fiber.join
Expand All @@ -1661,7 +1661,7 @@ trait StringsSpec extends IntegrationSpec {
key <- uuid
value <- uuid
_ <- redis.sAdd(key, "a")
_ <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireSeconds(1.second)))
_ <- redis.set(key, value, expireAt = Some(SetExpire.Seconds(1)))
existsBefore <- redis.exists(key)
fiber <- ZIO.sleep(1010.millis).fork <* TestClock.adjust(1010.millis)
_ <- fiber.join
Expand All @@ -1673,15 +1673,15 @@ trait StringsSpec extends IntegrationSpec {
redis <- ZIO.service[Redis]
key <- uuid
value <- uuid
result <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireSeconds(0.seconds))).either
result <- redis.set(key, value, expireAt = Some(SetExpire.Seconds(0))).either
} yield assert(result)(isLeft(isSubtype[ProtocolError](anything)))
},
test("error when negative ttl") {
for {
redis <- ZIO.service[Redis]
key <- uuid
value <- uuid
result <- redis.set(key, value, expireAt = Some(SetExpire.SetExpireSeconds((-1).second))).either
result <- redis.set(key, value, expireAt = Some(SetExpire.Seconds(-1))).either
} yield assert(result)(isLeft(isSubtype[ProtocolError](anything)))
}
),
Expand Down Expand Up @@ -1785,7 +1785,7 @@ trait StringsSpec extends IntegrationSpec {
key <- uuid
value <- uuid
_ <- redis.set(key, value)
exists <- redis.getEx(key, GetExpire.GetExpireSeconds(1.second)).returning[String]
exists <- redis.getEx(key, GetExpire.Seconds(1)).returning[String]
fiber <- ZIO.sleep(1020.millis).fork <* TestClock.adjust(1020.millis)
_ <- fiber.join
res <- redis.get(key).returning[String]
Expand All @@ -1797,7 +1797,7 @@ trait StringsSpec extends IntegrationSpec {
key <- uuid
value <- uuid
_ <- redis.set(key, value)
exists <- redis.getEx(key, GetExpire.GetExpireMilliseconds(10.millis)).returning[String]
exists <- redis.getEx(key, GetExpire.Milliseconds(10)).returning[String]
fiber <- ZIO.sleep(20.millis).fork <* TestClock.adjust(20.millis)
_ <- fiber.join
res <- redis.get(key).returning[String]
Expand All @@ -1810,7 +1810,7 @@ trait StringsSpec extends IntegrationSpec {
value <- uuid
_ <- redis.set(key, value)
expiresAt <- Clock.instant.map(_.plusMillis(10.millis.toMillis))
exists <- redis.getEx(key, GetExpire.GetExpireUnixTimeSeconds(expiresAt)).returning[String]
exists <- redis.getEx(key, GetExpire.UnixTimeSeconds(expiresAt.getEpochSecond)).returning[String]
fiber <- ZIO.sleep(20.millis).fork <* TestClock.adjust(20.millis)
_ <- fiber.join
res <- redis.get(key).returning[String]
Expand All @@ -1823,7 +1823,7 @@ trait StringsSpec extends IntegrationSpec {
value <- uuid
_ <- redis.set(key, value)
expiresAt <- Clock.instant.map(_.plusMillis(10.millis.toMillis))
exists <- redis.getEx(key, GetExpire.GetExpireUnixTimeMilliseconds(expiresAt)).returning[String]
exists <- redis.getEx(key, GetExpire.UnixTimeMilliseconds(expiresAt.toEpochMilli)).returning[String]
fiber <- ZIO.sleep(20.millis).fork <* TestClock.adjust(20.millis)
_ <- fiber.join
res <- redis.get(key).returning[String]
Expand All @@ -1836,8 +1836,8 @@ trait StringsSpec extends IntegrationSpec {
value <- uuid
_ <- redis.set(key, value)
expiresAt <- Clock.instant.map(_.plusMillis(10.millis.toMillis))
res <- redis.getEx(value, GetExpire.GetExpireUnixTimeMilliseconds(expiresAt)).returning[String]
res2 <- redis.getEx(value, GetExpire.GetExpireMilliseconds(10.millis)).returning[String]
res <- redis.getEx(value, GetExpire.UnixTimeMilliseconds(expiresAt.toEpochMilli)).returning[String]
res2 <- redis.getEx(value, GetExpire.Milliseconds(10)).returning[String]
} yield assert(res)(isNone) && assert(res2)(isNone)
} @@ flaky
),
Expand Down
56 changes: 33 additions & 23 deletions modules/redis/src/main/scala/zio/redis/Input.scala
Original file line number Diff line number Diff line change
Expand Up @@ -215,22 +215,32 @@ object Input {
final case class GetExInput[K: BinaryCodec]() extends Input[(K, GetExpire)] {
def encode(data: (K, GetExpire)): RespCommand =
data match {
case (key, GetExpire.GetExpireSeconds(duration)) =>
RespCommand(RespCommandArgument.Key(key), RespCommandArgument.Literal("EX")) ++ DurationSecondsInput.encode(
duration
case (key, GetExpire.Milliseconds(milliseconds)) =>
RespCommand(
RespCommandArgument.Key(key),
RespCommandArgument.Literal("PX"),
RespCommandArgument.Value(milliseconds.toString)
)
case (key, GetExpire.GetExpireMilliseconds(duration)) =>
RespCommand(RespCommandArgument.Key(key), RespCommandArgument.Literal("PX")) ++ DurationMillisecondsInput
.encode(duration)
case (key, GetExpire.GetExpireUnixTimeMilliseconds(instant)) =>
RespCommand(RespCommandArgument.Key(key), RespCommandArgument.Literal("PXAT")) ++ TimeMillisecondsInput
.encode(instant)
case (key, GetExpire.GetExpireUnixTimeSeconds(instant)) =>
RespCommand(RespCommandArgument.Key(key), RespCommandArgument.Literal("EXAT")) ++ TimeSecondsInput.encode(
instant
)
case (key, GetExpire.Persist) =>
case (key, GetExpire.Persist) =>
RespCommand(RespCommandArgument.Key(key), RespCommandArgument.Literal("PERSIST"))
case (key, GetExpire.Seconds(seconds)) =>
RespCommand(
RespCommandArgument.Key(key),
RespCommandArgument.Literal("EX"),
RespCommandArgument.Value(seconds.toString)
)
case (key, GetExpire.UnixTimeMilliseconds(milliseconds)) =>
RespCommand(
RespCommandArgument.Key(key),
RespCommandArgument.Literal("PXAT"),
RespCommandArgument.Value(milliseconds.toString)
)
case (key, GetExpire.UnixTimeSeconds(seconds)) =>
RespCommand(
RespCommandArgument.Key(key),
RespCommandArgument.Literal("EXAT"),
RespCommandArgument.Value(seconds.toString)
)
}
}

Expand Down Expand Up @@ -409,16 +419,16 @@ object Input {
case object SetExpireInput extends Input[SetExpire] {
def encode(data: SetExpire): RespCommand =
data match {
case SetExpire.KeepTtl =>
case SetExpire.KeepTtl =>
RespCommand(RespCommandArgument.Literal("KEEPTTL"))
case SetExpire.SetExpireSeconds(duration) =>
RespCommand(RespCommandArgument.Literal("EX")) ++ DurationSecondsInput.encode(duration)
case SetExpire.SetExpireMilliseconds(duration) =>
RespCommand(RespCommandArgument.Literal("PX")) ++ DurationMillisecondsInput.encode(duration)
case SetExpire.SetExpireUnixTimeMilliseconds(instant) =>
RespCommand(RespCommandArgument.Literal("PXAT")) ++ TimeMillisecondsInput.encode(instant)
case SetExpire.SetExpireUnixTimeSeconds(instant) =>
RespCommand(RespCommandArgument.Literal("EXAT")) ++ TimeSecondsInput.encode(instant)
case SetExpire.Milliseconds(milliseconds) =>
RespCommand(RespCommandArgument.Literal("PX"), RespCommandArgument.Value(milliseconds.toString))
case SetExpire.Seconds(seconds) =>
RespCommand(RespCommandArgument.Literal("EX"), RespCommandArgument.Value(seconds.toString))
case SetExpire.UnixTimeMilliseconds(milliseconds) =>
RespCommand(RespCommandArgument.Literal("PXAT"), RespCommandArgument.Value(milliseconds.toString))
case SetExpire.UnixTimeSeconds(seconds) =>
RespCommand(RespCommandArgument.Literal("EXAT"), RespCommandArgument.Value(seconds.toString))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ trait Connection[G[+_]] extends RedisEnvironment[G] {

/**
* Authenticates the current connection to the server in two cases:
* - If the Redis server is password protected via the the ''requirepass'' option
* - If the Redis server is password protected via the ''requirepass'' option
* - If a Redis 6.0 instance, or greater, is using the [[https://redis.io/topics/acl Redis ACL system]]. In this
* case it is assumed that the implicit username is ''default''.
*
Expand Down
4 changes: 2 additions & 2 deletions modules/redis/src/main/scala/zio/redis/api/SortedSets.scala
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ trait SortedSets[G[+_]] extends RedisEnvironment[G] {
* @param memberScore
* Score that should be added to specific element for a given sorted set key
* @param memberScores
* Rest scores that should be added to specific elements fr a given sorted set key
* Rest scores that should be added to specific elements for a given sorted set key
* @return
* The number of elements added to the sorted set, not including elements already existing for which the score was
* updated.
Expand Down Expand Up @@ -769,7 +769,7 @@ trait SortedSets[G[+_]] extends RedisEnvironment[G] {
* @param members
* Rest members to be removed
* @return
* The number of members removed from the sorted set, not including non existing members.
* The number of members removed from the sorted set, not including non-existing members.
*/
final def zRem[K: Schema, M: Schema](key: K, member: M, members: M*): G[Long] = {
val command =
Expand Down
4 changes: 2 additions & 2 deletions modules/redis/src/main/scala/zio/redis/api/Streams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ trait Streams[G[+_]] extends RedisEnvironment[G] {
Tuple3(OptionalInput(CountInput), OptionalInput(BlockInput), StreamsInput[SK, I]()),
ChunkOutput(StreamOutput[SK, I, RK, RV]())
)
command.run((count.map(Count(_)), block, (stream, Chunk.fromIterable(streams))))
command.run((count.map(Count), block, (stream, Chunk.fromIterable(streams))))
}
}

Expand Down Expand Up @@ -781,7 +781,7 @@ trait Streams[G[+_]] extends RedisEnvironment[G] {
)

val noAckOpt = if (noAck) Some(NoAck) else None
command.run((group, consumer, count.map(Count(_)), block, noAckOpt, (stream, Chunk.fromIterable(streams))))
command.run((group, consumer, count.map(Count), block, noAckOpt, (stream, Chunk.fromIterable(streams))))
}
}

Expand Down
22 changes: 10 additions & 12 deletions modules/redis/src/main/scala/zio/redis/options/Strings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package zio.redis.options

import zio.Duration

import java.time.Instant

trait Strings {
Expand Down Expand Up @@ -100,21 +98,21 @@ trait Strings {
sealed trait SetExpire

object SetExpire {
case object KeepTtl extends SetExpire
case class SetExpireMilliseconds(duration: Duration) extends SetExpire
case class SetExpireSeconds(duration: Duration) extends SetExpire
case class SetExpireUnixTimeMilliseconds(instant: Instant) extends SetExpire
case class SetExpireUnixTimeSeconds(instant: Instant) extends SetExpire
case object KeepTtl extends SetExpire
final case class Milliseconds(milliseconds: Long) extends SetExpire
final case class Seconds(seconds: Long) extends SetExpire
final case class UnixTimeMilliseconds(milliseconds: Long) extends SetExpire
final case class UnixTimeSeconds(seconds: Instant) extends SetExpire
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to prevent negative inputs. Also, you missed one Instant

}

sealed trait GetExpire

object GetExpire {
case class GetExpireMilliseconds(duration: Duration) extends GetExpire
case class GetExpireSeconds(duration: Duration) extends GetExpire
case class GetExpireUnixTimeMilliseconds(instant: Instant) extends GetExpire
case class GetExpireUnixTimeSeconds(instant: Instant) extends GetExpire
case object Persist extends GetExpire
final case class Milliseconds(milliseconds: Long) extends GetExpire
case object Persist extends GetExpire
final case class Seconds(seconds: Long) extends GetExpire
final case class UnixTimeMilliseconds(milliseconds: Long) extends GetExpire
final case class UnixTimeSeconds(seconds: Long) extends GetExpire
}

case object GetKeyword {
Expand Down
22 changes: 12 additions & 10 deletions modules/redis/src/test/scala/zio/redis/InputSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1300,28 +1300,30 @@ object InputSpec extends BaseSpec {
test("GetExInput - valid value") {
for {
resultSeconds <-
ZIO.attempt(GetExInput[String]().encode(scala.Tuple2("key", GetExpire.GetExpireSeconds(1.second))))
ZIO.attempt(GetExInput[String]().encode(scala.Tuple2("key", GetExpire.Seconds(1))))
resultMilliseconds <-
ZIO.attempt(GetExInput[String]().encode(scala.Tuple2("key", GetExpire.GetExpireMilliseconds(100.millis))))
ZIO.attempt(GetExInput[String]().encode(scala.Tuple2("key", GetExpire.Milliseconds(100))))
resultUnixTimeSeconds <-
ZIO.attempt(
GetExInput[String]().encode(
scala.Tuple2("key", GetExpire.GetExpireUnixTimeSeconds(Instant.parse("2021-04-06T00:00:00Z")))
scala.Tuple2("key", GetExpire.UnixTimeSeconds(Instant.parse("2021-04-06T00:00:00Z").getEpochSecond))
)
)
resultUnixTimeMilliseconds <-
ZIO.attempt(
GetExInput[String]().encode(
scala.Tuple2("key", GetExpire.GetExpireUnixTimeMilliseconds(Instant.parse("2021-04-06T00:00:00Z")))
scala
.Tuple2("key", GetExpire.UnixTimeMilliseconds(Instant.parse("2021-04-06T00:00:00Z").toEpochMilli))
)
)
resultPersist <- ZIO.attempt(GetExInput[String]().encode(scala.Tuple2("key", GetExpire.Persist)))
} yield assert(resultSeconds)(equalTo(RespCommand(Key("key"), Literal("EX"), Value("1")))) &&
assert(resultMilliseconds)(equalTo(RespCommand(Key("key"), Literal("PX"), Value("100")))) &&
assert(resultUnixTimeSeconds)(equalTo(RespCommand(Key("key"), Literal("EXAT"), Value("1617667200")))) &&
assert(resultUnixTimeMilliseconds)(
equalTo(RespCommand(Key("key"), Literal("PXAT"), Value("1617667200000")))
) && assert(resultPersist)(equalTo(RespCommand(Key("key"), Literal("PERSIST"))))
} yield assertTrue(
resultSeconds == RespCommand(Key("key"), Literal("EX"), Value("1")),
resultMilliseconds == RespCommand(Key("key"), Literal("PX"), Value("100")),
resultUnixTimeSeconds == RespCommand(Key("key"), Literal("EXAT"), Value("1617667200")),
resultUnixTimeMilliseconds == RespCommand(Key("key"), Literal("PXAT"), Value("1617667200000")),
resultPersist == RespCommand(Key("key"), Literal("PERSIST"))
)
}
)
)
Expand Down
Loading