Convert periodic tasks

This commit is contained in:
Eike Kettner 2020-12-11 23:15:18 +01:00
parent 3cef932ccd
commit 1aa1f4367e
7 changed files with 126 additions and 110 deletions

View File

@ -20,6 +20,8 @@ object Condition {
val P: Put[A]
) extends Condition
case class IsNull(col: Column[_]) extends Condition
case class And(c: Condition, cs: Vector[Condition]) extends Condition
case class Or(c: Condition, cs: Vector[Condition]) extends Condition
case class Not(c: Condition) extends Condition

View File

@ -94,14 +94,12 @@ trait DSL extends DoobieMeta {
def ===(value: A)(implicit P: Put[A]): Condition =
Condition.CompareVal(col, Operator.Eq, value)
//TODO find some better way around the cast
def ====(value: String): Condition =
Condition.CompareVal(col.asInstanceOf[Column[String]], Operator.Eq, value)
def like(value: A)(implicit P: Put[A]): Condition =
Condition.CompareVal(col, Operator.LowerLike, value)
//TODO find some better way around the cast
def likes(value: String): Condition =
Condition.CompareVal(col.asInstanceOf[Column[String]], Operator.LowerLike, value)
@ -117,6 +115,9 @@ trait DSL extends DoobieMeta {
def <(value: A)(implicit P: Put[A]): Condition =
Condition.CompareVal(col, Operator.Lt, value)
def <>(value: A)(implicit P: Put[A]): Condition =
Condition.CompareVal(col, Operator.Neq, value)
def in(subsel: Select): Condition =
Condition.InSubSelect(col, subsel)
@ -126,6 +127,9 @@ trait DSL extends DoobieMeta {
def inLower(values: NonEmptyList[A])(implicit P: Put[A]): Condition =
Condition.InValues(col, values, true)
def isNull: Condition =
Condition.IsNull(col)
def ===(other: Column[A]): Condition =
Condition.CompareCol(col, Operator.Eq, other)
}

View File

@ -5,6 +5,7 @@ sealed trait Operator
object Operator {
case object Eq extends Operator
case object Neq extends Operator
case object Gt extends Operator
case object Lt extends Operator
case object Gte extends Operator

View File

@ -44,6 +44,9 @@ object ConditionBuilder {
.map(a => buildValue(a)(c.P))
.reduce(_ ++ comma ++ _) ++ sql")"
case Condition.IsNull(col) =>
SelectExprBuilder.column(col) ++ fr" is null"
case Condition.And(c, cs) =>
val inner = cs.prepended(c).map(build).reduce(_ ++ and ++ _)
if (cs.isEmpty) inner
@ -54,6 +57,9 @@ object ConditionBuilder {
if (cs.isEmpty) inner
else parenOpen ++ inner ++ parenClose
case Condition.Not(Condition.IsNull(col)) =>
SelectExprBuilder.column(col) ++ fr" is not null"
case Condition.Not(c) =>
fr"NOT" ++ build(c)
}
@ -62,6 +68,8 @@ object ConditionBuilder {
op match {
case Operator.Eq =>
fr" ="
case Operator.Neq =>
fr" <>"
case Operator.Gt =>
fr" >"
case Operator.Lt =>

View File

@ -1,7 +1,8 @@
package docspell.store.queries
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.qb.DSL._
import docspell.store.qb._
import docspell.store.records._
import doobie._
@ -9,47 +10,47 @@ import doobie.implicits._
object QPeriodicTask {
def clearWorkers(name: Ident): ConnectionIO[Int] = {
val worker = RPeriodicTask.Columns.worker
updateRow(RPeriodicTask.table, worker.is(name), worker.setTo[Ident](None)).update.run
}
private val RT = RPeriodicTask.T
def setWorker(pid: Ident, name: Ident, ts: Timestamp): ConnectionIO[Int] = {
val id = RPeriodicTask.Columns.id
val worker = RPeriodicTask.Columns.worker
val marked = RPeriodicTask.Columns.marked
updateRow(
RPeriodicTask.table,
and(id.is(pid), worker.isNull),
commas(worker.setTo(name), marked.setTo(ts))
).update.run
}
def clearWorkers(name: Ident): ConnectionIO[Int] =
DML.update(
RT,
RT.worker === name,
DML.set(RT.worker.setTo(None: Option[Ident]))
)
def setWorker(pid: Ident, name: Ident, ts: Timestamp): ConnectionIO[Int] =
DML
.update(
RT,
RT.id === pid && RT.worker.isNull,
DML.set(
RT.worker.setTo(name),
RT.marked.setTo(ts)
)
)
def unsetWorker(
pid: Ident,
nextRun: Option[Timestamp]
): ConnectionIO[Int] = {
val id = RPeriodicTask.Columns.id
val worker = RPeriodicTask.Columns.worker
val next = RPeriodicTask.Columns.nextrun
updateRow(
RPeriodicTask.table,
id.is(pid),
commas(worker.setTo[Ident](None), next.setTo(nextRun))
).update.run
}
): ConnectionIO[Int] =
DML.update(
RT,
RT.id === pid,
DML.set(
RT.worker.setTo(None),
RT.nextrun.setTo(nextRun)
)
)
def findNext(excl: Option[Ident]): ConnectionIO[Option[RPeriodicTask]] = {
val enabled = RPeriodicTask.Columns.enabled
val pid = RPeriodicTask.Columns.id
val order = orderBy(RPeriodicTask.Columns.nextrun.f) ++ fr"ASC"
val where = excl match {
case Some(id) => and(pid.isNot(id), enabled.is(true))
case None => enabled.is(true)
case Some(id) => RT.id <> id && RT.enabled === true
case None => RT.enabled === true
}
val sql =
selectSimple(RPeriodicTask.Columns.all, RPeriodicTask.table, where) ++ order
Select(select(RT.all), from(RT), where).orderBy(RT.nextrun.asc).run
sql.query[RPeriodicTask].streamWithChunkSize(2).take(1).compile.last
}
}

View File

@ -3,33 +3,34 @@ package docspell.store.queries
import fs2._
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.qb.DSL._
import docspell.store.qb._
import docspell.store.records._
import docspell.store.usertask.UserTask
import doobie._
object QUserTask {
private val cols = RPeriodicTask.Columns
private val RT = RPeriodicTask.T
def findAll(account: AccountId): Stream[ConnectionIO, UserTask[String]] =
selectSimple(
RPeriodicTask.Columns.all,
RPeriodicTask.table,
and(cols.group.is(account.collective), cols.submitter.is(account.user))
run(
select(RT.all),
from(RT),
RT.group === account.collective && RT.submitter === account.user
).query[RPeriodicTask].stream.map(makeUserTask)
def findByName(
account: AccountId,
name: Ident
): Stream[ConnectionIO, UserTask[String]] =
selectSimple(
RPeriodicTask.Columns.all,
RPeriodicTask.table,
and(
cols.group.is(account.collective),
cols.submitter.is(account.user),
cols.task.is(name)
run(
select(RT.all),
from(RT),
where(
RT.group === account.collective,
RT.submitter === account.user,
RT.task === name
)
).query[RPeriodicTask].stream.map(makeUserTask)
@ -37,13 +38,13 @@ object QUserTask {
account: AccountId,
id: Ident
): ConnectionIO[Option[UserTask[String]]] =
selectSimple(
RPeriodicTask.Columns.all,
RPeriodicTask.table,
and(
cols.group.is(account.collective),
cols.submitter.is(account.user),
cols.id.is(id)
run(
select(RT.all),
from(RT),
where(
RT.group === account.collective,
RT.submitter === account.user,
RT.id === id
)
).query[RPeriodicTask].option.map(_.map(makeUserTask))
@ -63,24 +64,25 @@ object QUserTask {
RPeriodicTask.exists(id)
def delete(account: AccountId, id: Ident): ConnectionIO[Int] =
deleteFrom(
RPeriodicTask.table,
and(
cols.group.is(account.collective),
cols.submitter.is(account.user),
cols.id.is(id)
DML
.delete(
RT,
where(
RT.group === account.collective,
RT.submitter === account.user,
RT.id === id
)
)
).update.run
def deleteAll(account: AccountId, name: Ident): ConnectionIO[Int] =
deleteFrom(
RPeriodicTask.table,
and(
cols.group.is(account.collective),
cols.submitter.is(account.user),
cols.task.is(name)
DML.delete(
RT,
where(
RT.group === account.collective,
RT.submitter === account.user,
RT.task === name
)
).update.run
)
def makeUserTask(r: RPeriodicTask): UserTask[String] =
UserTask(r.id, r.task, r.enabled, r.timer, r.args)

View File

@ -4,8 +4,8 @@ import cats.effect._
import cats.implicits._
import docspell.common._
import docspell.store.impl.Column
import docspell.store.impl.Implicits._
import docspell.store.qb.DSL._
import docspell.store.qb._
import com.github.eikek.calev.CalEvent
import doobie._
@ -107,22 +107,22 @@ object RPeriodicTask {
)(implicit E: Encoder[A]): F[RPeriodicTask] =
create[F](enabled, task, group, E(args).noSpaces, subject, submitter, priority, timer)
val table = fr"periodic_task"
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "periodic_task"
object Columns {
val id = Column("id")
val enabled = Column("enabled")
val task = Column("task")
val group = Column("group_")
val args = Column("args")
val subject = Column("subject")
val submitter = Column("submitter")
val priority = Column("priority")
val worker = Column("worker")
val marked = Column("marked")
val timer = Column("timer")
val nextrun = Column("nextrun")
val created = Column("created")
val id = Column[Ident]("id", this)
val enabled = Column[Boolean]("enabled", this)
val task = Column[Ident]("task", this)
val group = Column[Ident]("group_", this)
val args = Column[String]("args", this)
val subject = Column[String]("subject", this)
val submitter = Column[Ident]("submitter", this)
val priority = Column[Priority]("priority", this)
val worker = Column[Ident]("worker", this)
val marked = Column[Timestamp]("marked", this)
val timer = Column[CalEvent]("timer", this)
val nextrun = Column[Timestamp]("nextrun", this)
val created = Column[Timestamp]("created", this)
val all = List(
id,
enabled,
@ -140,39 +140,37 @@ object RPeriodicTask {
)
}
import Columns._
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
def insert(v: RPeriodicTask): ConnectionIO[Int] = {
val sql = insertRow(
table,
all,
def insert(v: RPeriodicTask): ConnectionIO[Int] =
DML.insert(
T,
T.all,
fr"${v.id},${v.enabled},${v.task},${v.group},${v.args}," ++
fr"${v.subject},${v.submitter},${v.priority},${v.worker}," ++
fr"${v.marked},${v.timer},${v.nextrun},${v.created}"
)
sql.update.run
}
def update(v: RPeriodicTask): ConnectionIO[Int] = {
val sql = updateRow(
table,
id.is(v.id),
commas(
enabled.setTo(v.enabled),
group.setTo(v.group),
args.setTo(v.args),
subject.setTo(v.subject),
submitter.setTo(v.submitter),
priority.setTo(v.priority),
worker.setTo(v.worker),
marked.setTo(v.marked),
timer.setTo(v.timer),
nextrun.setTo(v.nextrun)
def update(v: RPeriodicTask): ConnectionIO[Int] =
DML.update(
T,
T.id === v.id,
DML.set(
T.enabled.setTo(v.enabled),
T.group.setTo(v.group),
T.args.setTo(v.args),
T.subject.setTo(v.subject),
T.submitter.setTo(v.submitter),
T.priority.setTo(v.priority),
T.worker.setTo(v.worker),
T.marked.setTo(v.marked),
T.timer.setTo(v.timer),
T.nextrun.setTo(v.nextrun)
)
)
sql.update.run
}
def exists(pid: Ident): ConnectionIO[Boolean] =
selectCount(id, table, id.is(pid)).query[Int].unique.map(_ > 0)
run(select(count(T.id)), from(T), T.id === pid).query[Int].unique.map(_ > 0)
}