All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avsystem.commons.redis.commands.lists.scala Maven / Gradle / Ivy

package com.avsystem.commons
package redis.commands

import com.avsystem.commons.redis.CommandEncoder.CommandArg
import com.avsystem.commons.redis._
import com.avsystem.commons.redis.commands.ReplyDecoders._

trait ListsApi extends ApiSubset {
  /** Executes [[http://redis.io/commands/lindex LINDEX]] */
  def lindex(key: Key, index: Long): Result[Opt[Value]] =
    execute(new Lindex(key, index))

  /** Executes [[http://redis.io/commands/linsert LINSERT]] */
  def linsert(key: Key, pivot: Value, value: Value, before: Boolean = false): Result[Opt[Long]] =
    execute(new Linsert(key, before, pivot, value))

  /** Executes [[http://redis.io/commands/llen LLEN]] */
  def llen(key: Key): Result[Long] =
    execute(new Llen(key))

  /** Executes [[http://redis.io/commands/lmove LMOVE]] */
  def lmove(source: Key, destination: Key, whereFrom: ListEnd, whereTo: ListEnd): Result[Opt[Value]] =
    execute(new Lmove(source, destination, whereFrom, whereTo))

  /** Executes [[http://redis.io/commands/lpop LPOP]] */
  def lpop(key: Key): Result[Opt[Value]] =
    execute(new Lpop(key))

  /** Executes [[http://redis.io/commands/lpos LPOS]] */
  def lpos(
    key: Key,
    element: Value,
    rank: OptArg[Long] = OptArg.Empty,
    maxlen: OptArg[Long] = OptArg.Empty
  ): Result[Opt[Long]] =
    execute(new Lpos(key, element, rank.toOpt, maxlen.toOpt))

  /** Executes [[http://redis.io/commands/lpos LPOS]] */
  def lposCount(
    key: Key,
    element: Value,
    count: Long,
    rank: OptArg[Long] = OptArg.Empty,
    maxlen: OptArg[Long] = OptArg.Empty
  ): Result[Seq[Long]] =
    execute(new LposCount(key, element, count, rank.toOpt, maxlen.toOpt))

  /** Executes [[http://redis.io/commands/lpush LPUSH]] */
  def lpush(key: Key, value: Value, values: Value*): Result[Long] =
    execute(new Lpush(key, value +:: values))

  /** Executes [[http://redis.io/commands/lpush LPUSH]]
    * NOTE: `values` MUST NOT be empty - consider using [[lpushOrLlen]] in such case. */
  def lpush(key: Key, values: Iterable[Value]): Result[Long] =
    execute(new Lpush(key, values))

  /** Executes [[http://redis.io/commands/lpush LPUSH]]
    * or [[http://redis.io/commands/llen LLEN]] when `values` is empty */
  def lpushOrLlen(key: Key, values: Iterable[Value]): Result[Long] =
    if (values.nonEmpty) lpush(key, values) else llen(key)

  /** Executes [[http://redis.io/commands/lpushx LPUSHX]] */
  def lpushx(key: Key, value: Value, values: Value*): Result[Long] =
    execute(new Lpushx(key, value +:: values))

  /** Executes [[http://redis.io/commands/lpushx LPUSHX]] */
  def lpushx(key: Key, values: Iterable[Value]): Result[Long] =
    execute(new Lpushx(key, values))

  /** Executes [[http://redis.io/commands/lpush LPUSHX]]
    * or [[http://redis.io/commands/llen LLEN]] when `values` is empty */
  def lpushxOrLlen(key: Key, values: Iterable[Value]): Result[Long] =
    if (values.nonEmpty) lpushx(key, values) else llen(key)

  /** Executes [[http://redis.io/commands/lrange LRANGE]] */
  def lrange(key: Key, start: Long = 0, stop: Long = -1): Result[Seq[Value]] =
    execute(new Lrange(key, start, stop))

  /** Executes [[http://redis.io/commands/lrem LREM]] */
  def lrem(key: Key, value: Value, count: RemCount = RemCount.All): Result[Long] =
    execute(new Lrem(key, count, value))

  /** Executes [[http://redis.io/commands/lset LSET]] */
  def lset(key: Key, index: Long, value: Value): Result[Unit] =
    execute(new Lset(key, index, value))

  /** Executes [[http://redis.io/commands/ltrim LTRIM]] */
  def ltrim(key: Key, start: Long = 0, stop: Long = -1): Result[Unit] =
    execute(new Ltrim(key, start, stop))

  /** Executes [[http://redis.io/commands/rpop RPOP]] */
  def rpop(key: Key): Result[Opt[Value]] =
    execute(new Rpop(key))

  /** Executes [[http://redis.io/commands/rpoplpush RPOPLPUSH]] */
  def rpoplpush(source: Key, destination: Key): Result[Opt[Value]] =
    execute(new Rpoplpush(source, destination))

  /** Executes [[http://redis.io/commands/rpush RPUSH]] */
  def rpush(key: Key, value: Value, values: Value*): Result[Long] =
    execute(new Rpush(key, value +:: values))

  /** Executes [[http://redis.io/commands/rpush RPUSH]]
    * NOTE: `values` MUST NOT be empty - consider using [[rpushOrLlen]] in such case. */
  def rpush(key: Key, values: Iterable[Value]): Result[Long] =
    execute(new Rpush(key, values))

  /** Executes [[http://redis.io/commands/lpush RPUSH]]
    * or [[http://redis.io/commands/llen LLEN]] when `values` is empty */
  def rpushOrLlen(key: Key, values: Iterable[Value]): Result[Long] =
    if (values.nonEmpty) rpush(key, values) else llen(key)

  /** Executes [[http://redis.io/commands/rpushx RPUSHX]] */
  def rpushx(key: Key, value: Value, values: Value*): Result[Long] =
    execute(new Rpushx(key, value +:: values))

  /** Executes [[http://redis.io/commands/rpushx RPUSHX]] */
  def rpushx(key: Key, values: Iterable[Value]): Result[Long] =
    execute(new Rpushx(key, values))

  /** Executes [[http://redis.io/commands/lpush RPUSHX]]
    * or [[http://redis.io/commands/llen LLEN]] when `values` is empty */
  def rpushxOrLlen(key: Key, values: Iterable[Value]): Result[Long] =
    if (values.nonEmpty) rpushx(key, values) else llen(key)

  /** Executes [[http://redis.io/commands/blpop BLPOP]] */
  def blpop(key: Key, timeout: Int): Result[Opt[Value]] =
    execute(new Blpop(key.single, timeout).map(_.map(_._2)))

  /** Executes [[http://redis.io/commands/blpop BLPOP]] */
  def blpop(keys: Iterable[Key], timeout: Int): Result[Opt[(Key, Value)]] =
    execute(new Blpop(keys, timeout))

  /** Executes [[http://redis.io/commands/brpop BRPOP]] */
  def brpop(key: Key, timeout: Int): Result[Opt[Value]] =
    execute(new Brpop(key.single, timeout).map(_.map(_._2)))

  /** Executes [[http://redis.io/commands/brpop BRPOP]] */
  def brpop(keys: Iterable[Key], timeout: Int): Result[Opt[(Key, Value)]] =
    execute(new Brpop(keys, timeout))

  /** Executes [[http://redis.io/commands/brpoplpush BRPOPLPUSH]] */
  def brpoplpush(source: Key, destination: Key, timeout: Int): Result[Opt[Value]] =
    execute(new Brpoplpush(source, destination, timeout))

  private final class Lindex(key: Key, index: Long) extends RedisOptDataCommand[Value] with NodeCommand {
    val encoded: Encoded = encoder("LINDEX").key(key).add(index).result
  }

  private final class Linsert(key: Key, before: Boolean, pivot: Value, value: Value)
    extends RedisPositiveLongCommand with NodeCommand {
    val encoded: Encoded = encoder("LINSERT").key(key).add(if (before) "BEFORE" else "AFTER").data(pivot).data(value).result
  }

  private final class Llen(key: Key) extends RedisLongCommand with NodeCommand {
    val encoded: Encoded = encoder("LLEN").key(key).result
  }

  private final class Lmove(source: Key, destination: Key, whereFrom: ListEnd, whereTo: ListEnd)
    extends RedisOptDataCommand[Value] with NodeCommand {
    val encoded: Encoded = encoder("LMOVE").key(source).key(destination).add(whereFrom).add(whereTo).result
  }

  private final class Lpop(key: Key) extends RedisOptDataCommand[Value] with NodeCommand {
    val encoded: Encoded = encoder("LPOP").key(key).result
  }

  private final class Lpos(key: Key, element: Value, rank: Opt[Long], maxlen: Opt[Long])
    extends RedisOptLongCommand with NodeCommand {
    val encoded: Encoded = encoder("LPOS").key(key).data(element)
      .optAdd("RANK", rank).optAdd("MAXLEN", maxlen).result
  }

  private final class LposCount(key: Key, element: Value, count: Long, rank: Opt[Long], maxlen: Opt[Long])
    extends RedisSeqCommand[Long](integerAsLong) with NodeCommand {
    val encoded: Encoded = encoder("LPOS").key(key).data(element)
      .add("COUNT").add(count).optAdd("RANK", rank).optAdd("MAXLEN", maxlen).result
  }

  private final class Lpush(key: Key, values: Iterable[Value]) extends RedisLongCommand with NodeCommand {
    val encoded: Encoded = encoder("LPUSH").key(key).datas(values).result
  }

  private final class Lpushx(key: Key, values: Iterable[Value]) extends RedisLongCommand with NodeCommand {
    val encoded: Encoded = encoder("LPUSHX").key(key).datas(values).result
  }

  private final class Lrange(key: Key, start: Long, stop: Long)
    extends RedisDataSeqCommand[Value] with NodeCommand {
    val encoded: Encoded = encoder("LRANGE").key(key).add(start).add(stop).result
  }

  private final class Lrem(key: Key, count: RemCount, value: Value) extends RedisLongCommand with NodeCommand {
    val encoded: Encoded = encoder("LREM").key(key).add(count.raw).data(value).result
  }

  private final class Lset(key: Key, index: Long, value: Value) extends RedisUnitCommand with NodeCommand {
    val encoded: Encoded = encoder("LSET").key(key).add(index).data(value).result
  }

  private final class Ltrim(key: Key, start: Long, stop: Long) extends RedisUnitCommand with NodeCommand {
    val encoded: Encoded = encoder("LTRIM").key(key).add(start).add(stop).result
  }

  private final class Rpop(key: Key) extends RedisOptDataCommand[Value] with NodeCommand {
    val encoded: Encoded = encoder("RPOP").key(key).result
  }

  private final class Rpoplpush(source: Key, destination: Key) extends RedisOptDataCommand[Value] with NodeCommand {
    val encoded: Encoded = encoder("RPOPLPUSH").key(source).key(destination).result
  }

  private final class Rpush(key: Key, values: Iterable[Value]) extends RedisLongCommand with NodeCommand {
    val encoded: Encoded = encoder("RPUSH").key(key).datas(values).result
  }

  private final class Rpushx(key: Key, values: Iterable[Value]) extends RedisLongCommand with NodeCommand {
    val encoded: Encoded = encoder("RPUSHX").key(key).datas(values).result
  }

  private final class Blpop(keys: Iterable[Key], timeout: Int)
    extends AbstractRedisCommand[Opt[(Key, Value)]](nullMultiBulkOr(multiBulkAsPair(bulkAs[Key], bulkAs[Value]))) with NodeCommand {
    val encoded: Encoded = encoder("BLPOP").keys(keys).add(timeout).result
    override def maxBlockingMillis: Int =
      if (timeout <= 0) Int.MaxValue else timeout * 1000
  }

  private final class Brpop(keys: Iterable[Key], timeout: Int)
    extends AbstractRedisCommand[Opt[(Key, Value)]](nullMultiBulkOr(multiBulkAsPair(bulkAs[Key], bulkAs[Value]))) with NodeCommand {
    val encoded: Encoded = encoder("BRPOP").keys(keys).add(timeout).result
    override def maxBlockingMillis: Int =
      if (timeout <= 0) Int.MaxValue else timeout * 1000
  }

  private final class Brpoplpush(source: Key, destination: Key, timeout: Int)
    extends AbstractRedisCommand[Opt[Value]](nullMultiBulkOr(bulkAs[Value])) with NodeCommand {
    val encoded: Encoded = encoder("BRPOPLPUSH").key(source).key(destination).add(timeout).result
    override def maxBlockingMillis: Int =
      if (timeout == 0) Int.MaxValue else timeout * 1000
  }
}

class RemCount private(val raw: Long) extends AnyVal {
  def count: Long = math.abs(raw)
  def fromHead: Boolean = raw > 0
  def fromTail: Boolean = raw < 0
}
object RemCount {
  def apply(count: Long, fromHead: Boolean): RemCount = {
    require(count > 0, "Count must be positive")
    new RemCount(if (fromHead) count else -count)
  }
  final val All = new RemCount(0)
  def fromHead(count: Long) = RemCount(count, fromHead = true)
  def fromTail(count: Long) = RemCount(count, fromHead = false)
}

sealed trait ListEnd extends Product with Serializable
object ListEnd {
  case object Left extends ListEnd
  case object Right extends ListEnd

  implicit val cmdArg: CommandArg[ListEnd] = CommandArg {
    case (ce, Left) => ce.add("LEFT")
    case (ce, Right) => ce.add("RIGHT")
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy