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

molly.core.query.SyncWatchQuery.scala Maven / Gradle / Ivy

There is a newer version: 0.5.9
Show newest version
package molly.core.query

import cats.effect.kernel.Async
import cats.effect.kernel.Sync
import cats.effect.syntax.spawn.*
import com.mongodb.client.ChangeStreamIterable
import com.mongodb.client.MongoChangeStreamCursor
import com.mongodb.client.model.changestream.ChangeStreamDocument
import com.mongodb.client.model.changestream.FullDocument
import fs2.Stream
import molly.core.MollyCodec
import org.bson.BsonDocument

import scala.concurrent.duration.*

final case class SyncWatchQuery[F[_], A] private[core] (private[core] val iterable: ChangeStreamIterable[BsonDocument])(
    using
    f: Async[F],
    codec: MollyCodec[F, A]
):

  /** [[https://mongodb.github.io/mongo-java-driver/5.1/apidocs/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ChangeStreamPublisher.html#resumeAfter(org.bson.BsonDocument)]]
    */
  def resumeAfter(resumeToken: BsonDocument): SyncWatchQuery[F, A] = SyncWatchQuery(iterable.resumeAfter(resumeToken))

  /** [[https://mongodb.github.io/mongo-java-driver/5.1/apidocs/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ChangeStreamPublisher.html#fullDocument(com.mongodb.client.model.changestream.FullDocument)]]
    */
  def fullDocument(fullDocument: FullDocument): SyncWatchQuery[F, A] =
    SyncWatchQuery(iterable.fullDocument(fullDocument))

  def list(bufferSize: Int = 16, timeout: FiniteDuration = 10.seconds): F[List[ChangeStreamDocument[A]]] =
    stream(bufferSize, timeout).compile.toList

  def stream(bufferSize: Int = 16, timeout: FiniteDuration = 10.seconds): Stream[F, ChangeStreamDocument[A]] =
    Stream
      .bracket(f.delay(iterable.batchSize(bufferSize).cursor()))(cursor => f.delay(cursor.close()))
      .flatMap(fromCursor(_, bufferSize, timeout))

  private type Cursor = MongoChangeStreamCursor[ChangeStreamDocument[BsonDocument]]

  private def fromCursor(cursor: Cursor, bufferSize: Int, timeout: FiniteDuration): Stream[F, ChangeStreamDocument[A]] =
    def getNext(cursor: Cursor): F[Option[(ChangeStreamDocument[BsonDocument], Cursor)]] =
      f.suspend(Sync.Type.Blocking)(if cursor.hasNext() then Some(cursor.next() -> cursor) else None)
        .cancelable(f.delay(cursor.close()))

    Stream
      .unfoldEval(cursor)(getNext)
      .evalMap(WatchQuery.decodeChangeStreamDocument)
      .groupWithin(bufferSize, timeout)
      .flatMap(Stream.chunk)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy