diff --git a/TODO b/TODO index 155be479f..8edc05a62 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,3 @@ -api/app/db/OriginalsDao.scala: private val parser: anorm.RowParser[InternalOriginal] = { - "org.webjars" % "bootstrap" % "3.4.1", webjars diff --git a/api/app/db/InternalOriginalsDao.scala b/api/app/db/InternalOriginalsDao.scala new file mode 100644 index 000000000..4d6e5824c --- /dev/null +++ b/api/app/db/InternalOriginalsDao.scala @@ -0,0 +1,50 @@ +package db + +import db.generated.OriginalsDao +import io.apibuilder.api.v0.models.{Original, OriginalType} + +import java.util.UUID +import javax.inject.Inject + +case class InternalOriginal(db: generated.Original) { + val id: Long = db.id + val versionGuid: UUID = db.versionGuid + val `type`: OriginalType = OriginalType(db.`type`) + val data: String = db.data +} + +class InternalOriginalsDao @Inject()(dao: OriginalsDao) { + + def create( + implicit c: java.sql.Connection, + user: InternalUser, + versionGuid: UUID, + original: Original + ): Unit = { + dao.insert(c, user.guid, generated.OriginalForm( + versionGuid = versionGuid, + `type` = original.`type`.toString, + data = original.data, + )) + } + + def softDeleteByVersionGuid( + implicit c: java.sql.Connection, + user: InternalUser, + versionGuid: UUID + ): Unit = { + dao.deleteAllByVersionGuid(c, user.guid, versionGuid) + } + + def findAllByVersionGuids(versionGuids: Seq[UUID]): Seq[InternalOriginal] = { + dao.findAll( + versionGuids = Some(versionGuids), + limit = None, + ) { q => q.isNull("deleted_at") }.map(InternalOriginal(_)) + } + + def findByVersionGuid(guid: UUID): Option[InternalOriginal] = { + findAllByVersionGuids(Seq(guid)).headOption + } + +} diff --git a/api/app/db/InternalVersionsDao.scala b/api/app/db/InternalVersionsDao.scala index c435784d8..6a56c648f 100644 --- a/api/app/db/InternalVersionsDao.scala +++ b/api/app/db/InternalVersionsDao.scala @@ -32,14 +32,14 @@ case class InternalVersion(db: generated.Version) { } class InternalVersionsDao @Inject()( - dao: VersionsDao, - applicationsDao: InternalApplicationsDao, - originalsDao: OriginalsDao, - tasksDao: InternalTasksDao, - usersDao: InternalUsersDao, - organizationsDao: InternalOrganizationsDao, - versionsModel: VersionsModel, - servicesDao: ServicesDao + dao: VersionsDao, + applicationsDao: InternalApplicationsDao, + originalsDao: InternalOriginalsDao, + tasksDao: InternalTasksDao, + usersDao: InternalUsersDao, + organizationsDao: InternalOrganizationsDao, + versionsModel: VersionsModel, + servicesDao: ServicesDao ) extends ValidatedHelpers { private val logger: Logger = Logger(this.getClass) diff --git a/api/app/db/OriginalsDao.scala b/api/app/db/OriginalsDao.scala deleted file mode 100644 index 76aafa957..000000000 --- a/api/app/db/OriginalsDao.scala +++ /dev/null @@ -1,84 +0,0 @@ -package db - -import io.apibuilder.api.v0.models.{Original, OriginalType, User} -import anorm.* -import db.generated.Version -import io.flow.postgresql.Query - -import javax.inject.Inject -import play.api.db.* -import play.api.libs.json.JsObject - -import java.util.UUID - -case class InternalOriginal(id: BigInt, versionGuid: UUID, `type`: OriginalType, data: String) - -class OriginalsDao @Inject() (db: Database) { - - private val InsertQuery = """ - insert into originals - (version_guid, type, data, created_by_guid) - values - ({version_guid}::uuid, {type}, {data}, {created_by_guid}::uuid) - """ - - private val SoftDeleteByVersionGuidQuery = """ - update originals - set deleted_at = now(), - deleted_by_guid = {deleted_by_guid}::uuid - where deleted_at is null - and version_guid = {version_guid}::uuid - """ - - def create( - implicit c: java.sql.Connection, - user: InternalUser, - versionGuid: UUID, - original: Original - ): Unit = { - SQL(InsertQuery).on( - "version_guid" -> versionGuid, - "type" -> original.`type`.toString, - "data" -> original.data, - "created_by_guid" -> user.guid - ).execute() - } - - def softDeleteByVersionGuid( - implicit c: java.sql.Connection, - user: InternalUser, - guid: UUID - ): Unit = { - SQL(SoftDeleteByVersionGuidQuery).on( - "version_guid" -> guid, - "deleted_by_guid" -> user.guid - ).execute() - } - - def findAllByVersionGuids(guids: Seq[UUID]): Seq[InternalOriginal] = { - db.withConnection { c => - Query("select id, version_guid::text, type, data from originals") - .in("version_guid", guids) - .isNull("deleted_at") - .as(parser.*)(c) - } - } - - def findByVersionGuid(guid: UUID): Option[InternalOriginal] = { - findAllByVersionGuids(Seq(guid)).headOption - } - - private val parser: anorm.RowParser[InternalOriginal] = { - anorm.SqlParser.long("id") ~ - anorm.SqlParser.str("version_guid") ~ - anorm.SqlParser.str("type") ~ - anorm.SqlParser.str("data") map { case id ~ versionGuid ~ typ ~ data => - InternalOriginal( - id = id, - versionGuid = java.util.UUID.fromString(versionGuid), - `type` = OriginalType(typ), - data = data - ) - } - } -} diff --git a/api/app/models/VersionsModel.scala b/api/app/models/VersionsModel.scala index d3563d986..ed6b86f6e 100644 --- a/api/app/models/VersionsModel.scala +++ b/api/app/models/VersionsModel.scala @@ -4,7 +4,7 @@ import builder.api_json.upgrades.ServiceParser import cats.data.Validated.{Invalid, Valid} import cats.data.ValidatedNec import cats.implicits.* -import db.{Authorization, InternalApplicationsDao, InternalOrganizationsDao, InternalVersion, OriginalsDao} +import db.{Authorization, InternalApplicationsDao, InternalOrganizationsDao, InternalVersion, InternalOriginalsDao} import db.generated.cache.ServicesDao import io.apibuilder.api.v0.models.Version import io.apibuilder.common.v0.models.{Audit, Reference, ReferenceGuid} @@ -17,7 +17,7 @@ import javax.inject.Inject class VersionsModel @Inject()( applicationsDao: InternalApplicationsDao, organizationsDao: InternalOrganizationsDao, - originalsDao: OriginalsDao, + originalsDao: InternalOriginalsDao, serviceParser: ServiceParser, servicesDao: ServicesDao, originalsModel: OriginalsModel diff --git a/api/test/util/Daos.scala b/api/test/util/Daos.scala index 11b8fa0d5..c59946db9 100644 --- a/api/test/util/Daos.scala +++ b/api/test/util/Daos.scala @@ -26,7 +26,7 @@ trait Daos { def organizationDomainsDao: InternalOrganizationDomainsDao = injector.instanceOf[db.InternalOrganizationDomainsDao] def organizationLogsDao: OrganizationLogsDao = injector.instanceOf[db.OrganizationLogsDao] def organizationsDao: InternalOrganizationsDao = injector.instanceOf[db.InternalOrganizationsDao] - def originalsDao: OriginalsDao = injector.instanceOf[db.OriginalsDao] + def originalsDao: InternalOriginalsDao = injector.instanceOf[db.InternalOriginalsDao] def passwordResetsDao: InternalPasswordResetsDao = injector.instanceOf[db.InternalPasswordResetsDao] def sessionsDao: SessionsDao = injector.instanceOf[SessionsDao] diff --git a/dao/spec/psql-apibuilder-generators.json b/dao/spec/psql-apibuilder-generators.json index af4294295..5109bad70 100644 --- a/dao/spec/psql-apibuilder-generators.json +++ b/dao/spec/psql-apibuilder-generators.json @@ -8,8 +8,7 @@ "package": "db.generated.generators", "user_class": "java.util.UUID", "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, diff --git a/dao/spec/psql-apibuilder.json b/dao/spec/psql-apibuilder.json index 18d2b55cf..24516370d 100644 --- a/dao/spec/psql-apibuilder.json +++ b/dao/spec/psql-apibuilder.json @@ -46,8 +46,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -75,8 +74,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -104,8 +102,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -148,8 +145,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -177,8 +173,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -221,8 +216,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -249,8 +243,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -282,8 +275,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -323,8 +315,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -364,8 +355,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -404,8 +394,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -435,8 +424,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -475,8 +463,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -516,8 +503,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -555,8 +541,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -598,8 +583,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -638,8 +622,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -680,8 +663,7 @@ "name": "scala", "value": { "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -721,8 +703,7 @@ "value": { "package": "db.generated.cache", "pkey_generator": { - "method": "java.util.UUID.randomUUID", - "returns": "uuid" + "method": "java.util.UUID.randomUUID" } } }, @@ -844,6 +825,48 @@ } } ] + }, + + "original": { + "fields": [ + { "name": "id", "type": "long" }, + { "name": "version_guid", "type": "uuid" }, + { "name": "type", "type": "string" }, + { "name": "data", "type": "string" } + ], + "attributes": [ + { + "name": "scala", + "value": { + "pkey_generator": { + "auto": true + } + } + }, + { + "name": "psql", + "value": { + "pkey": "id", + "audit": { + "created": { + "at": { "type": "date-time-iso8601" }, + "by": { "name": "created_by_guid", "type": "uuid" } + }, + "updated": { + "at": { "type": "date-time-iso8601" } + }, + "deleted": { + "at": { "type": "date-time-iso8601", "required": false }, + "by": { "name": "deleted_by_guid", "type": "uuid", "required": false } + } + }, + "indexes": [ + { "fields": ["version_guid"] }, + { "fields": ["version_guid"], "where": "deleted_at is null", "unique": true } + ] + } + } + ] } } } diff --git a/generated/app/db/OriginalsDao.scala b/generated/app/db/OriginalsDao.scala new file mode 100644 index 000000000..a9858d366 --- /dev/null +++ b/generated/app/db/OriginalsDao.scala @@ -0,0 +1,493 @@ +package db.generated + +case class Original( + id: Long, + versionGuid: java.util.UUID, + `type`: String, + data: String, + createdAt: org.joda.time.DateTime, + createdByGuid: java.util.UUID, + updatedAt: org.joda.time.DateTime, + deletedAt: Option[org.joda.time.DateTime], + deletedByGuid: Option[java.util.UUID] +) { + def form: OriginalForm = { + OriginalForm( + versionGuid = versionGuid, + `type` = `type`, + data = data, + ) + } +} + +case class OriginalForm( + versionGuid: java.util.UUID, + `type`: String, + data: String +) + +case object OriginalsTable { + val SchemaName: String = "public" + + val TableName: String = "originals" + + val QualifiedName: String = "public.originals" + + sealed trait Column { + def name: String + } + + object Columns { + case object Id extends Column { + override val name: String = "id" + } + + case object VersionGuid extends Column { + override val name: String = "version_guid" + } + + case object Type extends Column { + override val name: String = "type" + } + + case object Data extends Column { + override val name: String = "data" + } + + case object CreatedAt extends Column { + override val name: String = "created_at" + } + + case object CreatedByGuid extends Column { + override val name: String = "created_by_guid" + } + + case object UpdatedAt extends Column { + override val name: String = "updated_at" + } + + case object DeletedAt extends Column { + override val name: String = "deleted_at" + } + + case object DeletedByGuid extends Column { + override val name: String = "deleted_by_guid" + } + + val all: List[Column] = List(Id, VersionGuid, Type, Data, CreatedAt, CreatedByGuid, UpdatedAt, DeletedAt, DeletedByGuid) + } +} + +trait BaseOriginalsDao { + import anorm.* + + import anorm.JodaParameterMetaData.* + + import anorm.postgresql.* + + def db: play.api.db.Database + + private val BaseQuery: io.flow.postgresql.Query = { + io.flow.postgresql.Query(""" + | select id, + | version_guid::text, + | type, + | data, + | created_at, + | created_by_guid::text, + | updated_at, + | deleted_at, + | deleted_by_guid::text + | from public.originals + |""".stripMargin.stripTrailing + ) + } + + def findAll( + id: Option[Long] = None, + ids: Option[Seq[Long]] = None, + versionGuid: Option[java.util.UUID] = None, + versionGuids: Option[Seq[java.util.UUID]] = None, + limit: Option[Long], + offset: Long = 0, + orderBy: Option[io.flow.postgresql.OrderBy] = None + )(implicit customQueryModifier: io.flow.postgresql.Query => io.flow.postgresql.Query = identity): Seq[Original] = { + db.withConnection { c => + findAllWithConnection(c, id, ids, versionGuid, versionGuids, limit, offset, orderBy) + } + } + + def findAllWithConnection( + c: java.sql.Connection, + id: Option[Long] = None, + ids: Option[Seq[Long]] = None, + versionGuid: Option[java.util.UUID] = None, + versionGuids: Option[Seq[java.util.UUID]] = None, + limit: Option[Long], + offset: Long = 0, + orderBy: Option[io.flow.postgresql.OrderBy] = None + )(implicit customQueryModifier: io.flow.postgresql.Query => io.flow.postgresql.Query = identity): Seq[Original] = { + customQueryModifier(BaseQuery) + .equals("originals.id", id) + .optionalIn("originals.id", ids) + .equals("originals.version_guid", versionGuid) + .optionalIn("originals.version_guid", versionGuids) + .optionalLimit(limit) + .offset(offset) + .orderBy(orderBy.flatMap(_.sql)) + .as(parser.*)(c) + } + + def iterateAll( + id: Option[Long] = None, + ids: Option[Seq[Long]] = None, + versionGuid: Option[java.util.UUID] = None, + versionGuids: Option[Seq[java.util.UUID]] = None, + pageSize: Long = 1000 + )(implicit customQueryModifier: io.flow.postgresql.Query => io.flow.postgresql.Query = identity): Iterator[Original] = { + assert(pageSize > 0, "pageSize must be > 0") + + def iterate(lastValue: Option[Original]): Iterator[Original] = { + val page: Seq[Original] = db.withConnection { c => + customQueryModifier(BaseQuery) + .equals("originals.id", id) + .optionalIn("originals.id", ids) + .equals("originals.version_guid", versionGuid) + .optionalIn("originals.version_guid", versionGuids) + .greaterThan("originals.id", lastValue.map(_.id)) + .orderBy("originals.id") + .limit(pageSize) + .as(parser.*)(c) + } + if (page.length >= pageSize) { + page.iterator ++ iterate(page.lastOption) + } else { + page.iterator + } + } + + iterate(None) + } + + def findById(id: Long): Option[Original] = { + db.withConnection { c => + findByIdWithConnection(c, id) + } + } + + def findByIdWithConnection( + c: java.sql.Connection, + id: Long + ): Option[Original] = { + findAllWithConnection( + c = c, + id = Some(id), + limit = Some(1) + ).headOption + } + + def findAllByVersionGuid(versionGuid: java.util.UUID): Seq[Original] = { + db.withConnection { c => + findAllByVersionGuidWithConnection(c, versionGuid) + } + } + + def findAllByVersionGuidWithConnection( + c: java.sql.Connection, + versionGuid: java.util.UUID + ): Seq[Original] = { + findAllWithConnection( + c = c, + versionGuid = Some(versionGuid), + limit = None + ) + } + + private val parser: anorm.RowParser[Original] = { + anorm.SqlParser.long("id") ~ + anorm.SqlParser.str("version_guid") ~ + anorm.SqlParser.str("type") ~ + anorm.SqlParser.str("data") ~ + anorm.SqlParser.get[org.joda.time.DateTime]("created_at") ~ + anorm.SqlParser.str("created_by_guid") ~ + anorm.SqlParser.get[org.joda.time.DateTime]("updated_at") ~ + anorm.SqlParser.get[org.joda.time.DateTime]("deleted_at").? ~ + anorm.SqlParser.str("deleted_by_guid").? map { case id ~ versionGuid ~ type_ ~ data ~ createdAt ~ createdByGuid ~ updatedAt ~ deletedAt ~ deletedByGuid => + Original( + id = id, + versionGuid = java.util.UUID.fromString(versionGuid), + `type` = type_, + data = data, + createdAt = createdAt, + createdByGuid = java.util.UUID.fromString(createdByGuid), + updatedAt = updatedAt, + deletedAt = deletedAt, + deletedByGuid = deletedByGuid.map { v => java.util.UUID.fromString(v) } + ) + } + } +} + +class OriginalsDao @javax.inject.Inject() (override val db: play.api.db.Database) extends BaseOriginalsDao { + import anorm.JodaParameterMetaData.* + + import anorm.postgresql.* + + private val InsertQuery: io.flow.postgresql.Query = { + io.flow.postgresql.Query(""" + | insert into public.originals + | (version_guid, type, data, created_at, created_by_guid, updated_at) + | values + | ({version_guid}::uuid, {type}, {data}, {created_at}::timestamptz, {created_by_guid}::uuid, {updated_at}::timestamptz) + """.stripMargin) + } + + private val UpdateQuery: io.flow.postgresql.Query = { + io.flow.postgresql.Query(""" + | update public.originals + | set version_guid = {version_guid}::uuid, + | type = {type}, + | data = {data}, + | updated_at = {updated_at}::timestamptz + | where id = {id}::bigint + """.stripMargin) + } + + private val DeleteQuery: io.flow.postgresql.Query = { + io.flow.postgresql.Query("update public.originals set deleted_at = {deleted_at}::timestamptz, deleted_by_guid = {deleted_by_guid}::uuid").isNull("deleted_at") + } + + def insert( + user: java.util.UUID, + form: OriginalForm + ): Unit = { + db.withConnection { c => + insert(c, user, form) + } + } + + def insert( + c: java.sql.Connection, + user: java.util.UUID, + form: OriginalForm + ): Unit = { + bindQuery(InsertQuery, user, form) + .bind("created_at", org.joda.time.DateTime.now) + .bind("created_by_guid", user) + .execute(c) + } + + def insertBatch( + user: java.util.UUID, + forms: Seq[OriginalForm] + ): Seq[Unit] = { + db.withConnection { c => + insertBatch(c, user, forms) + } + } + + def insertBatch( + c: java.sql.Connection, + user: java.util.UUID, + forms: Seq[OriginalForm] + ): Seq[Unit] = { + forms.map { f => Seq(anorm.NamedParameter("created_at", org.joda.time.DateTime.now)) ++ toNamedParameter(user, f) }.toList match { + case Nil => Nil + case one :: rest => { + anorm.BatchSql(InsertQuery.sql(), one, rest*).execute()(c) + (Seq(one) ++ rest).map { _ => () } + } + } + } + + def update( + user: java.util.UUID, + original: Original, + form: OriginalForm + ): Unit = { + db.withConnection { c => + update(c, user, original, form) + } + } + + def update( + c: java.sql.Connection, + user: java.util.UUID, + original: Original, + form: OriginalForm + ): Unit = { + updateById( + c = c, + user = user, + id = original.id, + form = form + ) + } + + def updateById( + user: java.util.UUID, + id: Long, + form: OriginalForm + ): Unit = { + db.withConnection { c => + updateById(c, user, id, form) + } + } + + def updateById( + c: java.sql.Connection, + user: java.util.UUID, + id: Long, + form: OriginalForm + ): Unit = { + bindQuery(UpdateQuery, user, form) + .bind("id", id) + .execute(c) + () + } + + def updateBatch( + user: java.util.UUID, + forms: Seq[OriginalForm] + ): Unit = { + db.withConnection { c => + updateBatch(c, user, forms) + } + } + + def updateBatch( + c: java.sql.Connection, + user: java.util.UUID, + forms: Seq[OriginalForm] + ): Unit = { + forms.map { f => toNamedParameter(user, f) }.toList match { + case Nil => // no-op + case first :: rest => anorm.BatchSql(UpdateQuery.sql(), first, rest*).execute()(c) + } + } + + def delete( + user: java.util.UUID, + original: Original + ): Unit = { + db.withConnection { c => + delete(c, user, original) + } + } + + def delete( + c: java.sql.Connection, + user: java.util.UUID, + original: Original + ): Unit = { + deleteById( + c = c, + user = user, + id = original.id + ) + } + + def deleteById( + user: java.util.UUID, + id: Long + ): Unit = { + db.withConnection { c => + deleteById(c, user, id) + } + } + + def deleteById( + c: java.sql.Connection, + user: java.util.UUID, + id: Long + ): Unit = { + DeleteQuery.equals("id", id) + .bind("deleted_at", org.joda.time.DateTime.now) + .bind("deleted_by_guid", user) + .execute(c) + } + + def deleteAllByIds( + user: java.util.UUID, + ids: Seq[Long] + ): Unit = { + db.withConnection { c => + deleteAllByIds(c, user, ids) + } + } + + def deleteAllByIds( + c: java.sql.Connection, + user: java.util.UUID, + ids: Seq[Long] + ): Unit = { + DeleteQuery.in("id", ids) + .bind("deleted_at", org.joda.time.DateTime.now) + .bind("deleted_by_guid", user) + .execute(c) + } + + def deleteAllByVersionGuid( + user: java.util.UUID, + versionGuid: java.util.UUID + ): Unit = { + db.withConnection { c => + deleteAllByVersionGuid(c, user, versionGuid) + } + } + + def deleteAllByVersionGuid( + c: java.sql.Connection, + user: java.util.UUID, + versionGuid: java.util.UUID + ): Unit = { + DeleteQuery.equals("version_guid", versionGuid) + .bind("deleted_at", org.joda.time.DateTime.now) + .bind("deleted_by_guid", user) + .execute(c) + } + + def deleteAllByVersionGuids( + user: java.util.UUID, + versionGuids: Seq[java.util.UUID] + ): Unit = { + db.withConnection { c => + deleteAllByVersionGuids(c, user, versionGuids) + } + } + + def deleteAllByVersionGuids( + c: java.sql.Connection, + user: java.util.UUID, + versionGuids: Seq[java.util.UUID] + ): Unit = { + DeleteQuery.in("version_guid", versionGuids) + .bind("deleted_at", org.joda.time.DateTime.now) + .bind("deleted_by_guid", user) + .execute(c) + } + + private def bindQuery( + query: io.flow.postgresql.Query, + user: java.util.UUID, + form: OriginalForm + ): io.flow.postgresql.Query = { + query + .bind("version_guid", form.versionGuid.toString) + .bind("type", form.`type`) + .bind("data", form.data) + .bind("updated_at", org.joda.time.DateTime.now) + } + + private def toNamedParameter( + user: java.util.UUID, + form: OriginalForm + ): Seq[anorm.NamedParameter] = { + Seq( + anorm.NamedParameter("version_guid", form.versionGuid.toString), + anorm.NamedParameter("type", form.`type`), + anorm.NamedParameter("data", form.data), + anorm.NamedParameter("updated_at", org.joda.time.DateTime.now) + ) + } +} \ No newline at end of file