Sketching some basic tests

This commit is contained in:
Eike Kettner 2021-02-24 00:22:45 +01:00
parent be5c7ffb88
commit c3cdec416c
5 changed files with 153 additions and 12 deletions

View File

@ -47,7 +47,8 @@ val sharedSettings = Seq(
val testSettings = Seq(
testFrameworks += new TestFramework("minitest.runner.Framework"),
libraryDependencies ++= Dependencies.miniTest ++ Dependencies.logging.map(_ % Test)
libraryDependencies ++= Dependencies.miniTest ++ Dependencies.logging.map(_ % Test),
Test / fork := true
)
lazy val noPublish = Seq(
@ -275,6 +276,9 @@ val query =
libraryDependencies +=
Dependencies.catsParseJS.value
)
.jsSettings(
Test / fork := false
)
.jvmSettings(
libraryDependencies +=
Dependencies.scalaJsStubs

View File

@ -15,4 +15,6 @@ object ItemQueryParser {
.map(_.toString)
.map(expr => ItemQuery(expr, Some(input.trim)))
def parseUnsafe(input: String): ItemQuery =
parse(input).fold(sys.error, identity)
}

View File

@ -1,11 +1,11 @@
package docspell.store.qb.generator
import java.time.{Instant, LocalDate}
import cats.data.NonEmptyList
import docspell.common._
import docspell.query.ItemQuery
import docspell.query.ItemQuery.Attr._
import docspell.query.ItemQuery.Property.{DateProperty, StringProperty}
import docspell.query.ItemQuery.{Attr, Expr, Operator, TagOperator}
import docspell.query.{Date, ItemQuery}
import docspell.query.ItemQuery._
import docspell.store.qb.{Operator => QOp, _}
import docspell.store.qb.DSL._
import docspell.store.records.{RCustomField, RCustomFieldValue, TagItemName}
@ -74,7 +74,7 @@ object ItemQueryGenerator {
case Expr.Exists(field) =>
anyColumn(tables)(field).isNotNull
case Expr.SimpleExpr(op, StringProperty(attr, value)) =>
case Expr.SimpleExpr(op, Property.StringProperty(attr, value)) =>
val col = stringColumn(tables)(attr)
op match {
case Operator.Like =>
@ -83,8 +83,13 @@ object ItemQueryGenerator {
Condition.CompareVal(col, makeOp(op), value)
}
case Expr.SimpleExpr(op, DateProperty(attr, value)) =>
val dt = Timestamp.atUtc(value.atStartOfDay())
case Expr.SimpleExpr(op, Property.DateProperty(attr, value)) =>
val dt = value match {
case Date.Local(year, month, day) =>
Timestamp.atUtc(LocalDate.of(year, month, day).atStartOfDay())
case Date.Millis(ms) =>
Timestamp(Instant.ofEpochMilli(ms))
}
val col = timestampColumn(tables)(attr)
Condition.CompareVal(col, makeOp(op), dt)
@ -135,13 +140,13 @@ object ItemQueryGenerator {
private def anyColumn(tables: Tables)(attr: Attr): Column[_] =
attr match {
case s: StringAttr =>
case s: Attr.StringAttr =>
stringColumn(tables)(s)
case t: DateAttr =>
case t: Attr.DateAttr =>
timestampColumn(tables)(t)
}
private def timestampColumn(tables: Tables)(attr: DateAttr) =
private def timestampColumn(tables: Tables)(attr: Attr.DateAttr) =
attr match {
case Attr.Date =>
tables.item.itemDate
@ -149,7 +154,7 @@ object ItemQueryGenerator {
tables.item.dueDate
}
private def stringColumn(tables: Tables)(attr: StringAttr): Column[String] =
private def stringColumn(tables: Tables)(attr: Attr.StringAttr): Column[String] =
attr match {
case Attr.ItemId => tables.item.id.cast[String]
case Attr.ItemName => tables.item.name

View File

@ -0,0 +1,67 @@
package docspell.store
import cats.effect._
import docspell.common.LenientUri
import docspell.store.impl.StoreImpl
import doobie._
import org.h2.jdbcx.JdbcConnectionPool
import scala.concurrent.ExecutionContext
trait StoreFixture {
def withStore(db: String)(code: Store[IO] => IO[Unit]): Unit = {
//StoreFixture.store(StoreFixture.memoryDB(db)).use(code).unsafeRunSync()
val jdbc = StoreFixture.memoryDB(db)
val xa = StoreFixture.globalXA(jdbc)
val store = new StoreImpl[IO](jdbc, xa)
store.migrate.unsafeRunSync()
code(store).unsafeRunSync()
}
def withXA(db: String)(code: Transactor[IO] => IO[Unit]): Unit =
StoreFixture.makeXA(StoreFixture.memoryDB(db)).use(code).unsafeRunSync()
}
object StoreFixture {
implicit def contextShift: ContextShift[IO] =
IO.contextShift(ExecutionContext.global)
def memoryDB(dbname: String): JdbcConfig =
JdbcConfig(
LenientUri.unsafe(
s"jdbc:h2:mem:$dbname;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1"
),
"sa",
""
)
def globalXA(jdbc: JdbcConfig): Transactor[IO] =
Transactor.fromDriverManager(
"org.h2.Driver",
jdbc.url.asString,
jdbc.user,
jdbc.password
)
def makeXA(jdbc: JdbcConfig): Resource[IO, Transactor[IO]] = {
def jdbcConnPool =
JdbcConnectionPool.create(jdbc.url.asString, jdbc.user, jdbc.password)
val makePool = Resource.make(IO(jdbcConnPool))(cp => IO(cp.dispose()))
for {
ec <- ExecutionContexts.cachedThreadPool[IO]
blocker <- Blocker[IO]
pool <- makePool
xa = Transactor.fromDataSource[IO].apply(pool, ec, blocker)
} yield xa
}
def store(jdbc: JdbcConfig): Resource[IO, Store[IO]] =
for {
xa <- makeXA(jdbc)
store = new StoreImpl[IO](jdbc, xa)
_ <- Resource.liftF(store.migrate)
} yield store
}

View File

@ -0,0 +1,63 @@
package docspell.store.generator
import java.time.LocalDate
import docspell.store.records._
import minitest._
import docspell.common._
import docspell.query.ItemQueryParser
import docspell.store.qb.DSL._
import docspell.store.qb.generator.{ItemQueryGenerator, Tables}
object ItemQueryGeneratorTest extends SimpleTestSuite {
import docspell.store.impl.DoobieMeta._
val tables = Tables(
RItem.as("i"),
ROrganization.as("co"),
RPerson.as("cp"),
RPerson.as("np"),
REquipment.as("ne"),
RFolder.as("f"),
RAttachment.as("a"),
RAttachmentMeta.as("m")
)
test("migration") {
val q = ItemQueryParser
.parseUnsafe("(& name:hello date>=2020-02-01 (| source=expense folder=test ))")
val cond = ItemQueryGenerator(tables, Ident.unsafe("coll"))(q)
val expect =
tables.item.name.like("hello") && tables.item.itemDate >= Timestamp.atUtc(
LocalDate.of(2020, 2, 1).atStartOfDay()
) && (tables.item.source === "expense" || tables.folder.name === "test")
assertEquals(cond, expect)
}
// test("migration2") {
// withStore("db2") { store =>
// val c = RCollective(
// Ident.unsafe("coll1"),
// CollectiveState.Active,
// Language.German,
// true,
// Timestamp.Epoch
// )
// val e =
// REquipment(
// Ident.unsafe("equip"),
// Ident.unsafe("coll1"),
// "name",
// Timestamp.Epoch,
// Timestamp.Epoch,
// None
// )
//
// for {
// _ <- store.transact(RCollective.insert(c))
// _ <- store.transact(REquipment.insert(e)).map(_ => ())
// } yield ()
// }
// }
}