diff options
author | vlad <vlad@driver.xyz> | 2017-06-30 12:29:54 -0700 |
---|---|---|
committer | vlad <vlad@driver.xyz> | 2017-06-30 12:29:54 -0700 |
commit | a997aa6539d1f0af4ab4fc395ff2033335da312a (patch) | |
tree | 4f24529cd0beed94368caafdc0bdbb5677184851 /src/main/scala/xyz/driver/pdsuicommon/db | |
parent | 5832f63b84d7388441d1200f2442dc1e9de0225c (diff) | |
download | rest-query-a997aa6539d1f0af4ab4fc395ff2033335da312a.tar.gz rest-query-a997aa6539d1f0af4ab4fc395ff2033335da312a.tar.bz2 rest-query-a997aa6539d1f0af4ab4fc395ff2033335da312a.zip |
Latest PDS UI utils
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuicommon/db')
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala | 6 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala | 13 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala | 2 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala | 9 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala | 28 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala (renamed from src/main/scala/xyz/driver/pdsuicommon/db/SqlContext.scala) | 17 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala | 64 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala | 36 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala | 5 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala | 11 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala | 23 | ||||
-rw-r--r-- | src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala | 15 |
12 files changed, 129 insertions, 100 deletions
diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala index 5dafc00..0af104e 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala @@ -4,12 +4,12 @@ import scala.concurrent.Future trait DbCommand { def runSync(): Unit - def runAsync(transactions: Transactions): Future[Unit] + def runAsync(transactions: DbIo): Future[Unit] } object DbCommand { val Empty: DbCommand = new DbCommand { - override def runSync(): Unit = {} - override def runAsync(transactions: Transactions): Future[Unit] = Future.successful(()) + override def runSync(): Unit = {} + override def runAsync(transactions: DbIo): Future[Unit] = Future.successful(()) } } diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala new file mode 100644 index 0000000..7c290d1 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala @@ -0,0 +1,13 @@ +package xyz.driver.pdsuicommon.db + +import scala.concurrent.Future + +/** + * Where queries should run + */ +trait DbIo { + def runAsync[T](f: => T): Future[T] + def runSync[T](f: => T): T = f + def runAsyncTx[T](f: => T): Future[T] + def runSyncTx[T](f: => T): Unit +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala index d779e10..d765833 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala @@ -2,7 +2,7 @@ package xyz.driver.pdsuicommon.db import xyz.driver.pdsuicommon.domain.Id -class EntityNotFoundException private (id: String, tableName: String) +class EntityNotFoundException(id: String, tableName: String) extends RuntimeException(s"Entity with id $id is not found in $tableName table") { def this(id: Id[_], tableName: String) = this(id.toString, tableName) diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala new file mode 100644 index 0000000..e5a628c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala @@ -0,0 +1,9 @@ +package xyz.driver.pdsuicommon.db + +import scala.concurrent.Future + +object FakeDbIo extends DbIo { + override def runAsync[T](f: => T): Future[T] = Future.successful(f) + override def runAsyncTx[T](f: => T): Future[T] = Future.successful(f) + override def runSyncTx[T](f: => T): Unit = f +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala new file mode 100644 index 0000000..44f177c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala @@ -0,0 +1,28 @@ +package xyz.driver.pdsuicommon.db + +import xyz.driver.pdsuicommon.logging._ + +import scala.concurrent.Future +import scala.util.{Failure, Success, Try} + +class JdbcDbIo(sqlContext: TransactionalContext) extends DbIo with PhiLogging { + + override def runAsync[T](f: => T): Future[T] = { + Future(f)(sqlContext.executionContext) + } + + override def runAsyncTx[T](f: => T): Future[T] = { + import sqlContext.executionContext + + Future(sqlContext.transaction(f)).andThen { + case Failure(e) => logger.error(phi"Can't run a transaction: $e") + } + } + + override def runSyncTx[T](f: => T): Unit = { + Try(sqlContext.transaction(f)) match { + case Success(_) => + case Failure(e) => logger.error(phi"Can't run a transaction: $e") + } + } +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SqlContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala index c929eae..768d1e3 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SqlContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala @@ -8,15 +8,15 @@ import javax.sql.DataSource import com.typesafe.config.Config import io.getquill._ import xyz.driver.pdsuicommon.concurrent.MdcExecutionContext -import xyz.driver.pdsuicommon.db.SqlContext.Settings +import xyz.driver.pdsuicommon.db.MySqlContext.Settings import xyz.driver.pdsuicommon.error.IncorrectIdException -import xyz.driver.pdsuicommon.logging.{PhiLogging, Unsafe} +import xyz.driver.pdsuicommon.logging._ import scala.concurrent.ExecutionContext import scala.util.control.NonFatal import scala.util.{Failure, Success, Try} -object SqlContext extends PhiLogging { +object MySqlContext extends PhiLogging { case class DbCredentials(user: String, password: String, @@ -33,20 +33,21 @@ object SqlContext extends PhiLogging { connectionAttemptsOnStartup: Int, threadPoolSize: Int) - def apply(settings: Settings): SqlContext = { + def apply(settings: Settings): MySqlContext = { // Prevent leaking credentials to a log Try(JdbcContextConfig(settings.connection).dataSource) match { - case Success(dataSource) => new SqlContext(dataSource, settings) + case Success(dataSource) => new MySqlContext(dataSource, settings) case Failure(NonFatal(e)) => logger.error(phi"Can not load dataSource, error: ${Unsafe(e.getClass.getName)}") throw new IllegalArgumentException("Can not load dataSource from config. Check your database and config") } } - } -class SqlContext(dataSource: DataSource with Closeable, settings: Settings) - extends MysqlJdbcContext[MysqlEscape](dataSource) with EntityExtractorDerivation[Literal] { +class MySqlContext(dataSource: DataSource with Closeable, settings: Settings) + extends MysqlJdbcContext[MysqlEscape](dataSource) + with TransactionalContext + with EntityExtractorDerivation[Literal] { private val tpe = Executors.newFixedThreadPool(settings.threadPoolSize) diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala index 6b7639a..e2936e3 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala @@ -2,12 +2,12 @@ package xyz.driver.pdsuicommon.db import java.sql.ResultSet +import xyz.driver.pdsuicommon.logging._ import io.getquill.{MySQLDialect, MysqlEscape} import scala.collection.breakOut -import scala.concurrent.{ExecutionContext, Future} -object MysqlQueryBuilder { +object MysqlQueryBuilder extends PhiLogging { import xyz.driver.pdsuicommon.db.QueryBuilder._ def apply[T](tableName: String, @@ -15,46 +15,44 @@ object MysqlQueryBuilder { nullableFields: Set[String], links: Set[TableLink], runner: Runner[T], - countRunner: CountRunner)(implicit ec: ExecutionContext): MysqlQueryBuilder[T] = { + countRunner: CountRunner): MysqlQueryBuilder[T] = { val parameters = MysqlQueryBuilderParameters( tableData = TableData(tableName, lastUpdateFieldName, nullableFields), links = links.map(x => x.foreignTableName -> x)(breakOut) ) - new MysqlQueryBuilder[T](parameters)(runner, countRunner, ec) + new MysqlQueryBuilder[T](parameters)(runner, countRunner) } def apply[T](tableName: String, lastUpdateFieldName: Option[String], nullableFields: Set[String], links: Set[TableLink], - extractor: (ResultSet) => T)(implicit sqlContext: SqlContext): MysqlQueryBuilder[T] = { - - val runner = (parameters: QueryBuilderParameters) => { - Future { - val (sql, binder) = parameters.toSql(namingStrategy = MysqlEscape) - sqlContext.executeQuery[T](sql, binder, { resultSet => - extractor(resultSet) - }) - }(sqlContext.executionContext) + extractor: (ResultSet) => T)(implicit sqlContext: MySqlContext): MysqlQueryBuilder[T] = { + + val runner: Runner[T] = { parameters => + val (sql, binder) = parameters.toSql(namingStrategy = MysqlEscape) + logger.trace(phi"Query for execute: ${Unsafe(sql)}") + sqlContext.executeQuery[T](sql, binder, { resultSet => + extractor(resultSet) + }) } - val countRunner = (parameters: QueryBuilderParameters) => { - Future { - val (sql, binder) = parameters.toSql(countQuery = true, namingStrategy = MysqlEscape) - sqlContext - .executeQuery[CountResult]( - sql, - binder, { resultSet => - val count = resultSet.getInt(1) - val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) { - Option(sqlContext.localDateTimeDecoder.decoder(2, resultSet)) - } else None - - (count, lastUpdate) - } - ) - .head - }(sqlContext.executionContext) + val countRunner: CountRunner = { parameters => + val (sql, binder) = parameters.toSql(countQuery = true, namingStrategy = MysqlEscape) + logger.trace(phi"Query for execute: ${Unsafe(sql)}") + sqlContext + .executeQuery[CountResult]( + sql, + binder, { resultSet => + val count = resultSet.getInt(1) + val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) { + Option(sqlContext.localDateTimeDecoder.decoder(2, resultSet)) + } else None + + (count, lastUpdate) + } + ) + .head } apply[T]( @@ -64,13 +62,12 @@ object MysqlQueryBuilder { links = links, runner = runner, countRunner = countRunner - )(sqlContext.executionContext) + ) } } class MysqlQueryBuilder[T](parameters: MysqlQueryBuilderParameters)(implicit runner: QueryBuilder.Runner[T], - countRunner: QueryBuilder.CountRunner, - ec: ExecutionContext) + countRunner: QueryBuilder.CountRunner) extends QueryBuilder[T, MySQLDialect, MysqlEscape](parameters) { def withFilter(newFilter: SearchFilterExpr): QueryBuilder[T, MySQLDialect, MysqlEscape] = { @@ -88,5 +85,4 @@ class MysqlQueryBuilder[T](parameters: MysqlQueryBuilderParameters)(implicit run def resetPagination: QueryBuilder[T, MySQLDialect, MysqlEscape] = { new MysqlQueryBuilder[T](parameters.copy(pagination = None)) } - } diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala index 733d355..f941627 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala @@ -9,15 +9,14 @@ import xyz.driver.pdsuicommon.db.Sorting.{Dimension, Sequential} import xyz.driver.pdsuicommon.db.SortingOrder.{Ascending, Descending} import scala.collection.mutable.ListBuffer -import scala.concurrent.{ExecutionContext, Future} object QueryBuilder { - type Runner[T] = (QueryBuilderParameters) => Future[Seq[T]] + type Runner[T] = QueryBuilderParameters => Seq[T] type CountResult = (Int, Option[LocalDateTime]) - type CountRunner = (QueryBuilderParameters) => Future[CountResult] + type CountRunner = QueryBuilderParameters => CountResult /** * Binder for PreparedStatement @@ -207,12 +206,14 @@ sealed trait QueryBuilderParameters { val bindings = ListBuffer[AnyRef]() val sqlPlaceholder = placeholder(dimension.name) - val formattedValues = values - .map { value => - bindings += value - sqlPlaceholder - } - .mkString(", ") + val formattedValues = if (values.nonEmpty) { + values + .map { value => + bindings += value + sqlPlaceholder + } + .mkString(", ") + } else "NULL" (s"${escapeDimension(dimension)} $sqlOp ($formattedValues)", bindings.toList) case Intersection(operands) => @@ -297,23 +298,18 @@ case class MysqlQueryBuilderParameters(tableData: QueryBuilder.TableData, abstract class QueryBuilder[T, D <: SqlIdiom, N <: NamingStrategy](val parameters: QueryBuilderParameters)( implicit runner: QueryBuilder.Runner[T], - countRunner: QueryBuilder.CountRunner, - ec: ExecutionContext) { + countRunner: QueryBuilder.CountRunner) { - def run: Future[Seq[T]] = runner(parameters) + def run: Seq[T] = runner(parameters) - def runCount: Future[QueryBuilder.CountResult] = countRunner(parameters) + def runCount: QueryBuilder.CountResult = countRunner(parameters) /** * Runs the query and returns total found rows without considering of pagination. */ - def runWithCount: Future[(Seq[T], Int, Option[LocalDateTime])] = { - val countFuture = runCount - val selectAllFuture = run - for { - (total, lastUpdate) <- countFuture - all <- selectAllFuture - } yield (all, total, lastUpdate) + def runWithCount: (Seq[T], Int, Option[LocalDateTime]) = { + val (total, lastUpdate) = runCount + (run, total, lastUpdate) } def withFilter(newFilter: SearchFilterExpr): QueryBuilder[T, D, N] diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala index 5144163..4b66f22 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala @@ -54,7 +54,7 @@ object SearchFilterExpr { } } - case class Intersection private (operands: Seq[SearchFilterExpr]) + final case class Intersection private (operands: Seq[SearchFilterExpr]) extends SearchFilterExpr with SearchFilterExprSeqOps { override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { @@ -80,7 +80,8 @@ object SearchFilterExpr { } } - case class Union private (operands: Seq[SearchFilterExpr]) extends SearchFilterExpr with SearchFilterExprSeqOps { + final case class Union private (operands: Seq[SearchFilterExpr]) + extends SearchFilterExpr with SearchFilterExprSeqOps { override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { if (f.isDefinedAt(this)) f(this) diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala new file mode 100644 index 0000000..9883b9e --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala @@ -0,0 +1,11 @@ +package xyz.driver.pdsuicommon.db + +import scala.concurrent.ExecutionContext + +trait TransactionalContext { + + implicit def executionContext: ExecutionContext + + def transaction[T](f: => T): T + +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala deleted file mode 100644 index 72c358a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging.PhiLogging - -import scala.concurrent.Future -import scala.util.{Failure, Success, Try} - -class Transactions()(implicit context: SqlContext) extends PhiLogging { - def run[T](f: SqlContext => T): Future[T] = { - import context.executionContext - - Future(context.transaction(f(context))).andThen { - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } - - def runSync[T](f: SqlContext => T): Unit = { - Try(context.transaction(f(context))) match { - case Success(_) => - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala index a3140a6..4c25afa 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala @@ -1,24 +1,21 @@ package xyz.driver.pdsuicommon.db.repositories import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue -import xyz.driver.pdsuicommon.domain.LongId - -import scala.concurrent.Future +import xyz.driver.pdsuicommon.db.MysqlQueryBuilder trait BridgeUploadQueueRepository extends Repository { type EntityT = BridgeUploadQueue.Item - type IdT = LongId[EntityT] def add(draft: EntityT): EntityT - def getById(id: LongId[EntityT]): Option[EntityT] - - def isCompleted(kind: String, tag: String): Future[Boolean] + def getById(kind: String, tag: String): Option[EntityT] - def getOne(kind: String): Future[Option[BridgeUploadQueue.Item]] + def getOne(kind: String): Option[BridgeUploadQueue.Item] def update(entity: EntityT): EntityT - def delete(id: IdT): Unit + def delete(kind: String, tag: String): Unit + + def buildQuery: MysqlQueryBuilder[EntityT] } |