imagnusson.kuzminki-pekko_2.13.0.9.5.source-code.stream.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2021 Kári Magnússon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kuzminki.pekko
import scala.concurrent.{Future, ExecutionContext}
import org.apache.pekko.{Done, NotUsed}
import org.apache.pekko.stream.scaladsl.{Source, Sink}
import shapeless._
import shapeless.ops.hlist.Tupler
import kuzminki.api.Kuzminki
import kuzminki.select.{Pages, Offset}
import kuzminki.insert.StoredInsert
import kuzminki.delete.StoredDelete
import kuzminki.update.StoredUpdate
package object stream {
implicit class InsertAsSink[P, B <: HList](query: StoredInsert[P]) {
def asSink(
implicit db: Kuzminki,
ec: ExecutionContext
): Sink[P, Future[Done]] = {
Sink.foreachAsync(1) { (p: P) =>
db.exec(query.render(p))
}
}
def asChunkSink(
implicit db: Kuzminki,
ec: ExecutionContext
): Sink[Seq[P], Future[Done]] = {
Sink.foreachAsync(1) { (chunk: Seq[P]) =>
db.execList(
chunk.map { (p: P) => query.render(p) }
)
}
}
def asTypeSink[T <: Product](
implicit generic: Generic.Aux[T, B],
tupler: Tupler.Aux[B, P],
db: Kuzminki,
ec: ExecutionContext
): Sink[T, Future[Done]] = {
Sink.foreachAsync(1) { (t: T) =>
db.exec(
query.render(
Generic[T].to(t).tupled
)
)
}
}
def asTypeChunkSink[T <: Product](
implicit generic: Generic.Aux[T, B],
tupler: Tupler.Aux[B, P],
db: Kuzminki,
ec: ExecutionContext
): Sink[Seq[T], Future[Done]] = {
Sink.foreachAsync(1) { (chunk: Seq[T]) =>
db.execList(
chunk.toList.map { (t: T) =>
query.render(
Generic[T].to(t).tupled
)
}
)
}
}
}
implicit class DeleteAsSink[P](query: StoredDelete[P]) {
def asSink(
implicit db: Kuzminki,
ec: ExecutionContext
): Sink[P, Future[Done]] = {
Sink.foreachAsync(1) { (p: P) =>
db.exec(query.render(p))
}
}
def asBatchSink(
implicit db: Kuzminki,
ec: ExecutionContext
): Sink[Seq[P], Future[Done]] = {
Sink.foreachAsync(1) { (chunk: Seq[P]) =>
db.execList(
chunk.map { (p: P) => query.render(p) }
)
}
}
}
implicit class UpdateAsSink[P1, P2](query: StoredUpdate[P1, P2]) {
def asSink(
implicit db: Kuzminki,
ec: ExecutionContext
): Sink[Tuple2[P1, P2], Future[Done]] = {
Sink.foreachAsync(1) { (p: Tuple2[P1, P2]) =>
db.exec(query.render(p._1, p._2))
}
}
def asChunkSink(
implicit db: Kuzminki,
ec: ExecutionContext
): Sink[Seq[Tuple2[P1, P2]], Future[Done]] = {
Sink.foreachAsync(1) { (chunk: Seq[Tuple2[P1, P2]]) =>
db.execList(
chunk.toList.map { (p: Tuple2[P1, P2]) =>
query.render(p._1, p._2)
}
)
}
}
}
implicit class RunAsSource[M, R, B <: HList](query: Offset[M, R]) {
def stream(implicit db: Kuzminki, ec: ExecutionContext): Source[R, NotUsed] = {
stream(100)
}
def stream(size: Int)(implicit db: Kuzminki, ec: ExecutionContext): Source[R, NotUsed] = {
val pages = Pages(query.render, size)
Source.unfoldAsync(pages) { pages =>
pages.next.map {
case Nil => None
case items => Some((pages, items))
}
}
.mapConcat(i => i)
}
def streamType[T <: Product](
implicit untupler: Generic.Aux[R, B],
generic: Generic.Aux[T, B],
db: Kuzminki,
ec: ExecutionContext
): Source[T, NotUsed] = {
stream.map((r: R) => generic.from(untupler.to(r)))
}
def streamType[T <: Product](size: Int)(
implicit untupler: Generic.Aux[R, B],
generic: Generic.Aux[T, B],
db: Kuzminki,
ec: ExecutionContext
): Source[T, NotUsed] = {
stream(size).map((r: R) => generic.from(untupler.to(r)))
}
}
}