mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-05 22:55:58 +00:00
Sketching some basic tests
This commit is contained in:
parent
be5c7ffb88
commit
c3cdec416c
@ -47,7 +47,8 @@ val sharedSettings = Seq(
|
|||||||
|
|
||||||
val testSettings = Seq(
|
val testSettings = Seq(
|
||||||
testFrameworks += new TestFramework("minitest.runner.Framework"),
|
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(
|
lazy val noPublish = Seq(
|
||||||
@ -275,6 +276,9 @@ val query =
|
|||||||
libraryDependencies +=
|
libraryDependencies +=
|
||||||
Dependencies.catsParseJS.value
|
Dependencies.catsParseJS.value
|
||||||
)
|
)
|
||||||
|
.jsSettings(
|
||||||
|
Test / fork := false
|
||||||
|
)
|
||||||
.jvmSettings(
|
.jvmSettings(
|
||||||
libraryDependencies +=
|
libraryDependencies +=
|
||||||
Dependencies.scalaJsStubs
|
Dependencies.scalaJsStubs
|
||||||
|
@ -15,4 +15,6 @@ object ItemQueryParser {
|
|||||||
.map(_.toString)
|
.map(_.toString)
|
||||||
.map(expr => ItemQuery(expr, Some(input.trim)))
|
.map(expr => ItemQuery(expr, Some(input.trim)))
|
||||||
|
|
||||||
|
def parseUnsafe(input: String): ItemQuery =
|
||||||
|
parse(input).fold(sys.error, identity)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package docspell.store.qb.generator
|
package docspell.store.qb.generator
|
||||||
|
|
||||||
|
import java.time.{Instant, LocalDate}
|
||||||
|
|
||||||
import cats.data.NonEmptyList
|
import cats.data.NonEmptyList
|
||||||
import docspell.common._
|
import docspell.common._
|
||||||
import docspell.query.ItemQuery
|
import docspell.query.{Date, ItemQuery}
|
||||||
import docspell.query.ItemQuery.Attr._
|
import docspell.query.ItemQuery._
|
||||||
import docspell.query.ItemQuery.Property.{DateProperty, StringProperty}
|
|
||||||
import docspell.query.ItemQuery.{Attr, Expr, Operator, TagOperator}
|
|
||||||
import docspell.store.qb.{Operator => QOp, _}
|
import docspell.store.qb.{Operator => QOp, _}
|
||||||
import docspell.store.qb.DSL._
|
import docspell.store.qb.DSL._
|
||||||
import docspell.store.records.{RCustomField, RCustomFieldValue, TagItemName}
|
import docspell.store.records.{RCustomField, RCustomFieldValue, TagItemName}
|
||||||
@ -74,7 +74,7 @@ object ItemQueryGenerator {
|
|||||||
case Expr.Exists(field) =>
|
case Expr.Exists(field) =>
|
||||||
anyColumn(tables)(field).isNotNull
|
anyColumn(tables)(field).isNotNull
|
||||||
|
|
||||||
case Expr.SimpleExpr(op, StringProperty(attr, value)) =>
|
case Expr.SimpleExpr(op, Property.StringProperty(attr, value)) =>
|
||||||
val col = stringColumn(tables)(attr)
|
val col = stringColumn(tables)(attr)
|
||||||
op match {
|
op match {
|
||||||
case Operator.Like =>
|
case Operator.Like =>
|
||||||
@ -83,8 +83,13 @@ object ItemQueryGenerator {
|
|||||||
Condition.CompareVal(col, makeOp(op), value)
|
Condition.CompareVal(col, makeOp(op), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Expr.SimpleExpr(op, DateProperty(attr, value)) =>
|
case Expr.SimpleExpr(op, Property.DateProperty(attr, value)) =>
|
||||||
val dt = Timestamp.atUtc(value.atStartOfDay())
|
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)
|
val col = timestampColumn(tables)(attr)
|
||||||
Condition.CompareVal(col, makeOp(op), dt)
|
Condition.CompareVal(col, makeOp(op), dt)
|
||||||
|
|
||||||
@ -135,13 +140,13 @@ object ItemQueryGenerator {
|
|||||||
|
|
||||||
private def anyColumn(tables: Tables)(attr: Attr): Column[_] =
|
private def anyColumn(tables: Tables)(attr: Attr): Column[_] =
|
||||||
attr match {
|
attr match {
|
||||||
case s: StringAttr =>
|
case s: Attr.StringAttr =>
|
||||||
stringColumn(tables)(s)
|
stringColumn(tables)(s)
|
||||||
case t: DateAttr =>
|
case t: Attr.DateAttr =>
|
||||||
timestampColumn(tables)(t)
|
timestampColumn(tables)(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def timestampColumn(tables: Tables)(attr: DateAttr) =
|
private def timestampColumn(tables: Tables)(attr: Attr.DateAttr) =
|
||||||
attr match {
|
attr match {
|
||||||
case Attr.Date =>
|
case Attr.Date =>
|
||||||
tables.item.itemDate
|
tables.item.itemDate
|
||||||
@ -149,7 +154,7 @@ object ItemQueryGenerator {
|
|||||||
tables.item.dueDate
|
tables.item.dueDate
|
||||||
}
|
}
|
||||||
|
|
||||||
private def stringColumn(tables: Tables)(attr: StringAttr): Column[String] =
|
private def stringColumn(tables: Tables)(attr: Attr.StringAttr): Column[String] =
|
||||||
attr match {
|
attr match {
|
||||||
case Attr.ItemId => tables.item.id.cast[String]
|
case Attr.ItemId => tables.item.id.cast[String]
|
||||||
case Attr.ItemName => tables.item.name
|
case Attr.ItemName => tables.item.name
|
||||||
|
@ -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
|
||||||
|
}
|
@ -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 ()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user