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

lightdb.async.AsyncCollection.scala Maven / Gradle / Ivy

package lightdb.async

import lightdb._
import lightdb.field.Field._
import lightdb.collection.Collection
import lightdb.doc.{Document, DocumentModel}
import lightdb.transaction.Transaction
import rapid.Task

import scala.util.{Failure, Success}

case class AsyncCollection[Doc <: Document[Doc], Model <: DocumentModel[Doc]](underlying: Collection[Doc, Model]) extends AnyVal {
  def transaction[Return](f: Transaction[Doc] => Task[Return]): Task[Return] = {
    val transaction = underlying.transaction.create()
    f(transaction).guarantee(Task {
      underlying.transaction.release(transaction)
    })
  }

  /**
   * Convenience feature for simple one-off operations removing the need to manually create a transaction around it.
   */
  def t: AsyncTransactionConvenience[Doc, Model] = AsyncTransactionConvenience(this)

  def insert(doc: Doc)(implicit transaction: Transaction[Doc]): Task[Doc] = Task(underlying.insert(doc))

  def insert(docs: Seq[Doc])(implicit transaction: Transaction[Doc]): Task[Seq[Doc]] = Task(underlying.insert(docs))

  def upsert(doc: Doc)(implicit transaction: Transaction[Doc]): Task[Doc] = Task(underlying.upsert(doc))

  def upsert(docs: Seq[Doc])(implicit transaction: Transaction[Doc]): Task[Seq[Doc]] = Task(underlying.upsert(docs))

  def get[V](f: Model => (UniqueIndex[Doc, V], V))(implicit transaction: Transaction[Doc]): Task[Option[Doc]] =
    Task(underlying.get(f))

  def apply[V](f: Model => (UniqueIndex[Doc, V], V))(implicit transaction: Transaction[Doc]): Task[Doc] =
    Task(underlying(f))

  def get(id: Id[Doc])(implicit transaction: Transaction[Doc]): Task[Option[Doc]] =
    Task(underlying.get(id))

  def getAll(ids: Seq[Id[Doc]])(implicit transaction: Transaction[Doc]): rapid.Stream[Doc] =
    rapid.Stream.fromIterator(Task(underlying.getAll(ids)))

  def apply(id: Id[Doc])(implicit transaction: Transaction[Doc]): Task[Doc] =
    Task(underlying(id))

  def withLock(id: Id[Doc], doc: Task[Option[Doc]], establishLock: Boolean = true)
           (f: Option[Doc] => Task[Option[Doc]]): Task[Option[Doc]] = if (establishLock) {
    doc.map(d => if (establishLock) underlying.lock.acquire(id, d) else d).flatMap { existing =>
      f(existing)
        .attempt
        .flatMap {
          case Success(modified) =>
            if (establishLock) underlying.lock.release(id, modified)
            Task.pure(modified)
          case Failure(err) =>
            if (establishLock) underlying.lock.release(id, existing)
            Task.error(err)
        }
    }
  } else {
    doc.flatMap(f)
  }

  def modify(id: Id[Doc], establishLock: Boolean = true, deleteOnNone: Boolean = false)
            (f: Option[Doc] => Task[Option[Doc]])
            (implicit transaction: Transaction[Doc]): Task[Option[Doc]] = withLock(id, get(id), establishLock) { existing =>
    f(existing).flatMap {
      case Some(doc) => upsert(doc).map(doc => Some(doc))
      case None if deleteOnNone => delete(id).map(_ => None)
      case None => Task.pure(None)
    }
  }

  def getOrCreate(id: Id[Doc], create: => Task[Doc], lock: Boolean = true)
                 (implicit transaction: Transaction[Doc]): Task[Doc] = modify(id, establishLock = lock) {
    case Some(doc) => Task.pure(Some(doc))
    case None => create.map(Some.apply)
  }.map(_.get)

  def delete[V](f: Model => (UniqueIndex[Doc, V], V))(implicit transaction: Transaction[Doc]): Task[Boolean] =
    Task(underlying.delete(f))

  def delete(id: Id[Doc])(implicit transaction: Transaction[Doc], ev: Model <:< DocumentModel[_]): Task[Boolean] =
    Task(underlying.delete(id))

  def count(implicit transaction: Transaction[Doc]): Task[Int] = Task(underlying.count)

  def stream(implicit transaction: Transaction[Doc]): rapid.Stream[Doc] =
    rapid.Stream.fromIterator(Task(underlying.iterator))

  def list(implicit transaction: Transaction[Doc]): Task[List[Doc]] = stream.toList

  def query: AsyncQuery[Doc, Model] = AsyncQuery(this)

  def truncate()(implicit transaction: Transaction[Doc]): Task[Int] = Task(underlying.truncate())

  def reIndex(): Task[Boolean] = Task(underlying.reIndex())

  def dispose(): Task[Unit] = Task(underlying.dispose())
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy