aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuicommon/db
diff options
context:
space:
mode:
authorvlad <vlad@driver.xyz>2017-06-30 12:29:54 -0700
committervlad <vlad@driver.xyz>2017-06-30 12:29:54 -0700
commita997aa6539d1f0af4ab4fc395ff2033335da312a (patch)
tree4f24529cd0beed94368caafdc0bdbb5677184851 /src/main/scala/xyz/driver/pdsuicommon/db
parent5832f63b84d7388441d1200f2442dc1e9de0225c (diff)
downloadrest-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.scala6
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala13
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala2
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala9
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala28
-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.scala64
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala36
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala5
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala11
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala23
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala15
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]
}