From 1aa1f4367e99f59cee52b1e0fed4d7a384600c37 Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Fri, 11 Dec 2020 23:15:18 +0100 Subject: [PATCH] Convert periodic tasks --- .../scala/docspell/store/qb/Condition.scala | 2 + .../main/scala/docspell/store/qb/DSL.scala | 8 +- .../scala/docspell/store/qb/Operator.scala | 1 + .../store/qb/impl/ConditionBuilder.scala | 8 ++ .../store/queries/QPeriodicTask.scala | 65 +++++++-------- .../docspell/store/queries/QUserTask.scala | 70 ++++++++-------- .../store/records/RPeriodicTask.scala | 82 +++++++++---------- 7 files changed, 126 insertions(+), 110 deletions(-) diff --git a/modules/store/src/main/scala/docspell/store/qb/Condition.scala b/modules/store/src/main/scala/docspell/store/qb/Condition.scala index 88a5487f..c1f623cb 100644 --- a/modules/store/src/main/scala/docspell/store/qb/Condition.scala +++ b/modules/store/src/main/scala/docspell/store/qb/Condition.scala @@ -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 diff --git a/modules/store/src/main/scala/docspell/store/qb/DSL.scala b/modules/store/src/main/scala/docspell/store/qb/DSL.scala index 7eb12b55..e399515b 100644 --- a/modules/store/src/main/scala/docspell/store/qb/DSL.scala +++ b/modules/store/src/main/scala/docspell/store/qb/DSL.scala @@ -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) } diff --git a/modules/store/src/main/scala/docspell/store/qb/Operator.scala b/modules/store/src/main/scala/docspell/store/qb/Operator.scala index c05559ca..907c2593 100644 --- a/modules/store/src/main/scala/docspell/store/qb/Operator.scala +++ b/modules/store/src/main/scala/docspell/store/qb/Operator.scala @@ -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 diff --git a/modules/store/src/main/scala/docspell/store/qb/impl/ConditionBuilder.scala b/modules/store/src/main/scala/docspell/store/qb/impl/ConditionBuilder.scala index 1f99df1e..2dfbd8a8 100644 --- a/modules/store/src/main/scala/docspell/store/qb/impl/ConditionBuilder.scala +++ b/modules/store/src/main/scala/docspell/store/qb/impl/ConditionBuilder.scala @@ -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 => diff --git a/modules/store/src/main/scala/docspell/store/queries/QPeriodicTask.scala b/modules/store/src/main/scala/docspell/store/queries/QPeriodicTask.scala index cf8451c5..46d8a273 100644 --- a/modules/store/src/main/scala/docspell/store/queries/QPeriodicTask.scala +++ b/modules/store/src/main/scala/docspell/store/queries/QPeriodicTask.scala @@ -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 } } diff --git a/modules/store/src/main/scala/docspell/store/queries/QUserTask.scala b/modules/store/src/main/scala/docspell/store/queries/QUserTask.scala index 9ef601fa..13fbbc89 100644 --- a/modules/store/src/main/scala/docspell/store/queries/QUserTask.scala +++ b/modules/store/src/main/scala/docspell/store/queries/QUserTask.scala @@ -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) diff --git a/modules/store/src/main/scala/docspell/store/records/RPeriodicTask.scala b/modules/store/src/main/scala/docspell/store/records/RPeriodicTask.scala index 4f7c68a3..e0dcdb3f 100644 --- a/modules/store/src/main/scala/docspell/store/records/RPeriodicTask.scala +++ b/modules/store/src/main/scala/docspell/store/records/RPeriodicTask.scala @@ -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) }