diff --git a/build.sc b/build.sc index cfe6016872..a80fdba152 100644 --- a/build.sc +++ b/build.sc @@ -158,13 +158,13 @@ object example extends Module{ object staticFiles2 extends Cross[StaticFiles2Module](scalaVersions) trait TodoModule extends millbuild.example.todo.build.AppModule with LocalModule - object todo extends Cross[TodoModule](scala212, scala213) // uses quill, can't enable for Dotty yet + object todo extends Cross[TodoModule](scala213) // uses quill, can't enable for Dotty yet trait TodoApiModule extends millbuild.example.todoApi.build.AppModule with LocalModule object todoApi extends Cross[TodoApiModule](scalaVersions) trait TodoDbModule extends millbuild.example.todoDb.build.AppModule with LocalModule - object todoDb extends Cross[TodoDbModule](scala212, scala213) // uses quill, can't enable for Dotty yet + object todoDb extends Cross[TodoDbModule](scala213) // uses quill, can't enable for Dotty yet trait TwirlModule extends millbuild.example.twirl.build.AppModule with LocalModule object twirl extends Cross[TwirlModule](scalaVersions) diff --git a/example/todo/app/src/TodoServer.scala b/example/todo/app/src/TodoServer.scala index c6622352fe..9489b64141 100644 --- a/example/todo/app/src/TodoServer.scala +++ b/example/todo/app/src/TodoServer.scala @@ -1,102 +1,96 @@ package app -import com.typesafe.config.ConfigFactory -import io.getquill.{SnakeCase, SqliteJdbcContext} -import io.getquill.context.ExecutionInfo +import scalasql.DbApi.Txn +import scalasql.Sc +import scalasql.SqliteDialect._ import scalatags.Text.all._ import scalatags.Text.tags2 object TodoServer extends cask.MainRoutes{ val tmpDb = java.nio.file.Files.createTempDirectory("todo-cask-sqlite") - object ctx extends SqliteJdbcContext( - SnakeCase, - ConfigFactory.parseString( - s"""{"driverClassName":"org.sqlite.JDBC","jdbcUrl":"jdbc:sqlite:$tmpDb/file.db"}""" - ) + val sqliteDataSource = new org.sqlite.SQLiteDataSource() + sqliteDataSource.setUrl(s"jdbc:sqlite:$tmpDb/file.db") + lazy val sqliteClient = new scalasql.DbClient.DataSource( + sqliteDataSource, + config = new scalasql.Config {} ) class transactional extends cask.RawDecorator{ class TransactionFailed(val value: cask.router.Result.Error) extends Exception def wrapFunction(pctx: cask.Request, delegate: Delegate) = { - try ctx.transaction( - delegate(Map()) match{ + try sqliteClient.transaction( txn => + delegate(Map("txn" -> txn)) match{ case cask.router.Result.Success(t) => cask.router.Result.Success(t) case e: cask.router.Result.Error => throw new TransactionFailed(e) } ) catch{case e: TransactionFailed => e.value} + } } - case class Todo(id: Int, checked: Boolean, text: String) + case class Todo[T[_]](id: T[Int], checked: T[Boolean], text: T[String]) + object Todo extends scalasql.Table[Todo] - ctx.executeAction( + sqliteClient.getAutoCommitClientConnection.updateRaw( """CREATE TABLE todo ( | id INTEGER PRIMARY KEY AUTOINCREMENT, | checked BOOLEAN, | text TEXT |); - |""".stripMargin - )(ExecutionInfo.unknown, ()) - ctx.executeAction( - """INSERT INTO todo (checked, text) VALUES + | + |INSERT INTO todo (checked, text) VALUES |(1, 'Get started with Cask'), |(0, 'Profit!'); |""".stripMargin - )(ExecutionInfo.unknown, ()) - - import ctx._ + ) @transactional @cask.post("/list/:state") - def list(state: String) = renderBody(state).render + def list(state: String)(txn: Txn) = renderBody(state)(txn).render @transactional @cask.post("/add/:state") - def add(state: String, request: cask.Request) = { + def add(state: String, request: cask.Request)(implicit txn: Txn) = { val body = request.text() - run( - query[Todo] - .insert(_.checked -> lift(false), _.text -> lift(body)) - .returningGenerated(_.id) - ) + txn.run(Todo.insert.columns(_.checked := false, _.text := body)) renderBody(state).render } @transactional @cask.post("/delete/:state/:index") - def delete(state: String, index: Int) = { - run(query[Todo].filter(_.id == lift(index)).delete) + def delete(state: String, index: Int)(implicit txn: Txn) = { + txn.run(Todo.delete(_.id === index)) renderBody(state).render } @transactional @cask.post("/toggle/:state/:index") - def toggle(state: String, index: Int) = { - run(query[Todo].filter(_.id == lift(index)).update(p => p.checked -> !p.checked)) + def toggle(state: String, index: Int)(implicit txn: Txn) = { + txn.run(Todo.update(_.id === index).set(p => p.checked := !p.checked)) renderBody(state).render } @transactional @cask.post("/clear-completed/:state") - def clearCompleted(state: String) = { - run(query[Todo].filter(_.checked).delete) + def clearCompleted(state: String)(implicit txn: Txn) = { + txn.run(Todo.delete(_.checked)) renderBody(state).render } @transactional @cask.post("/toggle-all/:state") - def toggleAll(state: String) = { - val next = run(query[Todo].filter(_.checked).size) != 0 - run(query[Todo].update(_.checked -> !lift(next))) + def toggleAll(state: String)(implicit txn: Txn) = { + val next = txn.run(Todo.select.filter(_.checked).size) != 0 + txn.run(Todo.update(_ => true).set(_.checked := !next)) renderBody(state).render } - def renderBody(state: String) = { + def renderBody(state: String)(implicit txn: Txn) = { val filteredTodos = state match{ - case "all" => run(query[Todo]).sortBy(-_.id) - case "active" => run(query[Todo].filter(!_.checked)).sortBy(-_.id) - case "completed" => run(query[Todo].filter(_.checked)).sortBy(-_.id) + case "all" => txn.run(Todo.select).sortBy(-_.id) + case "active" => txn.run(Todo.select.filter(!_.checked)).sortBy(-_.id) + case "completed" => txn.run(Todo.select.filter(_.checked)).sortBy(-_.id) } frag( header(cls := "header", @@ -108,7 +102,7 @@ object TodoServer extends cask.MainRoutes{ id := "toggle-all", cls := "toggle-all", `type` := "checkbox", - if (run(query[Todo].filter(_.checked).size != 0)) checked else () + if (txn.run(Todo.select.filter(_.checked).size !== 0)) checked else () ), label(`for` := "toggle-all","Mark all as complete"), ul(cls := "todo-list", @@ -130,7 +124,7 @@ object TodoServer extends cask.MainRoutes{ ), footer(cls := "footer", span(cls := "todo-count", - strong(run(query[Todo].filter(!_.checked).size).toInt), + strong(txn.run(Todo.select.filter(!_.checked).size).toInt), " items left" ), ul(cls := "filters", @@ -151,7 +145,7 @@ object TodoServer extends cask.MainRoutes{ @transactional @cask.get("/") - def index() = { + def index()(implicit txn: Txn) = { doctype("html")( html(lang := "en", head( diff --git a/example/todo/build.sc b/example/todo/build.sc index d50b963b8b..19d2486230 100644 --- a/example/todo/build.sc +++ b/example/todo/build.sc @@ -4,7 +4,7 @@ trait AppModule extends CrossScalaModule{ def ivyDeps = Agg[Dep]( ivy"org.xerial:sqlite-jdbc:3.42.0.0", - ivy"io.getquill::quill-jdbc:4.6.1", + ivy"com.lihaoyi::scalasql:0.1.0", ivy"com.lihaoyi::scalatags:0.12.0", ivy"org.slf4j:slf4j-simple:1.7.30", ) diff --git a/example/todoDb/app/src/TodoMvcDb.scala b/example/todoDb/app/src/TodoMvcDb.scala index 826224197c..b78781fa4a 100644 --- a/example/todoDb/app/src/TodoMvcDb.scala +++ b/example/todoDb/app/src/TodoMvcDb.scala @@ -1,23 +1,22 @@ package app -import com.typesafe.config.ConfigFactory -import io.getquill.{SqliteJdbcContext, SnakeCase} -import io.getquill.context.ExecutionInfo +import scalasql.DbApi.Txn +import scalasql.Sc +import scalasql.SqliteDialect._ object TodoMvcDb extends cask.MainRoutes{ val tmpDb = java.nio.file.Files.createTempDirectory("todo-cask-sqlite") - - object ctx extends SqliteJdbcContext( - SnakeCase, - ConfigFactory.parseString( - s"""{"driverClassName":"org.sqlite.JDBC","jdbcUrl":"jdbc:sqlite:$tmpDb/file.db"}""" - ) + val sqliteDataSource = new org.sqlite.SQLiteDataSource() + sqliteDataSource.setUrl(s"jdbc:sqlite:$tmpDb/file.db") + lazy val sqliteClient = new scalasql.DbClient.DataSource( + sqliteDataSource, + config = new scalasql.Config {} ) class transactional extends cask.RawDecorator{ class TransactionFailed(val value: cask.router.Result.Error) extends Exception def wrapFunction(pctx: cask.Request, delegate: Delegate) = { - try ctx.transaction( - delegate(Map()) match{ + try sqliteClient.transaction( txn => + delegate(Map("txn" -> txn)) match{ case cask.router.Result.Success(t) => cask.router.Result.Success(t) case e: cask.router.Result.Error => throw new TransactionFailed(e) } @@ -27,60 +26,58 @@ object TodoMvcDb extends cask.MainRoutes{ } } - case class Todo(id: Int, checked: Boolean, text: String) - object Todo{ - implicit def todoRW = upickle.default.macroRW[Todo] + case class Todo[T[_]](id: T[Int], checked: T[Boolean], text: T[String]) + object Todo extends scalasql.Table[Todo]{ + implicit def todoRW = upickle.default.macroRW[Todo[Sc]] } - ctx.executeAction( + sqliteClient.getAutoCommitClientConnection.updateRaw( """CREATE TABLE todo ( | id INTEGER PRIMARY KEY AUTOINCREMENT, | checked BOOLEAN, | text TEXT |); - |""".stripMargin - )(ExecutionInfo.unknown, ()) - ctx.executeAction( - """INSERT INTO todo (checked, text) VALUES + | + |INSERT INTO todo (checked, text) VALUES |(1, 'Get started with Cask'), |(0, 'Profit!'); |""".stripMargin - )(ExecutionInfo.unknown, ()) - - import ctx._ + ) @transactional @cask.get("/list/:state") - def list(state: String) = { + def list(state: String)(txn: Txn) = { val filteredTodos = state match{ - case "all" => run(query[Todo]) - case "active" => run(query[Todo].filter(!_.checked)) - case "completed" => run(query[Todo].filter(_.checked)) + case "all" => txn.run(Todo.select) + case "active" => txn.run(Todo.select.filter(!_.checked)) + case "completed" => txn.run(Todo.select.filter(_.checked)) } upickle.default.write(filteredTodos) } @transactional @cask.post("/add") - def add(request: cask.Request) = { + def add(request: cask.Request)(txn: Txn) = { val body = request.text() - run( - query[Todo] - .insert(_.checked -> lift(false), _.text -> lift(body)) - .returningGenerated(_.id) + txn.run( + Todo + .insert + .columns(_.checked := false, _.text := body) + .returning(_.id) + .single ) } @transactional @cask.post("/toggle/:index") - def toggle(index: Int) = { - run(query[Todo].filter(_.id == lift(index)).update(p => p.checked -> !p.checked)) + def toggle(index: Int)(txn: Txn) = { + txn.run(Todo.update(_.id === index).set(p => p.checked := !p.checked)) } @transactional @cask.post("/delete/:index") - def delete(index: Int) = { - run(query[Todo].filter(_.id == lift(index)).delete) + def delete(index: Int)(txn: Txn) = { + txn.run(Todo.delete(_.id === index)) } initialize() diff --git a/example/todoDb/build.sc b/example/todoDb/build.sc index 071ca9cbeb..893b424be9 100644 --- a/example/todoDb/build.sc +++ b/example/todoDb/build.sc @@ -4,8 +4,7 @@ trait AppModule extends CrossScalaModule{ def ivyDeps = Agg[Dep]( ivy"org.xerial:sqlite-jdbc:3.42.0.0", - ivy"io.getquill::quill-jdbc:4.6.1", - ivy"org.slf4j:slf4j-simple:1.7.30" + ivy"com.lihaoyi::scalasql:0.1.0", ) object test extends ScalaTests with TestModule.Utest{