playframework / play-slick Goto Github PK
View Code? Open in Web Editor NEWSlick Plugin for Play
License: Apache License 2.0
Slick Plugin for Play
License: Apache License 2.0
In tests it is possible to use different DB.session , for example :
DB("test").withSession { implicit session =>
// my test query
}
The loaded datasource will be the one defined with db.test.*
in application.conf.
This is fine, but If you want to test some controllers or models that use DB.withSession (and not DB("test").withSession ) you will be binded to the default datasource, not to the test datasource.
Maybe it will be solved in the same time that #14 with the session wrapping, but I add the issue for reminder.
I have this implicit to convert from sql.Date to util.Date
implicit val dateTypeMapper = MappedTypeMapper.base[java.util.Date, java.sql.Date](
{ jud => new java.sql.Date(jud.getTime) },
{ jsd => jsd })
When defined in the package object, it compiles, but fails at runtime (when generating the DDL) with a method not found error.
See this gist for the complete source code :https://gist.github.com/tyrcho/5086544
I am not sure if this is related to Slick or not but if I have several tests and one looks like this:
package test
import org.specs2.mutable._
import play.api.test._
import play.api.test.Helpers._
/**
* add your integration spec here.
* An integration test will fire up a whole play application in a real (or headless) browser
*/
class IntegrationSpec extends Specification {
"Application" should {
"work from within a browser" in {
running(TestServer(3333), HTMLUNIT) { browser =>
browser.goTo("http://localhost:3333/")
true
}
}
}
}
It fails with:
play.api.Application$$anon$1: Execution exception[[SQLException: Attempting to obtain a connection from a pool that has already been shutdown.
Stack trace of location where pool was shutdown follows:
java.lang.Thread.getStackTrace(Thread.java:1503)
com.jolbox.bonecp.BoneCP.captureStackTrace(BoneCP.java:543)
com.jolbox.bonecp.BoneCP.shutdown(BoneCP.java:159)
com.jolbox.bonecp.BoneCPDataSource.close(BoneCPDataSource.java:123)
play.api.db.BoneCPApi.shutdownPool(DB.scala:405)
play.api.db.BoneCPPlugin$$anonfun$onStop$1.liftedTree1$1(DB.scala:263)
play.api.db.BoneCPPlugin$$anonfun$onStop$1.apply(DB.scala:262)
play.api.db.BoneCPPlugin$$anonfun$onStop$1.apply(DB.scala:261)
scala.collection.immutable.List.foreach(List.scala:309)
play.api.db.BoneCPPlugin.onStop(DB.scala:261)
play.api.Play$$anonfun$stop$1$$anonfun$apply$1$$anonfun$apply$mcV$sp$2.apply(Play.scala:80)
play.api.Play$$anonfun$stop$1$$anonfun$apply$1$$anonfun$apply$mcV$sp$2.apply(Play.scala:79)
scala.collection.immutable.List.foreach(List.scala:309)
play.api.Play$$anonfun$stop$1$$anonfun$apply$1.apply$mcV$sp(Play.scala:79)
play.api.Play$$anonfun$stop$1$$anonfun$apply$1.apply(Play.scala:79)
play.api.Play$$anonfun$stop$1$$anonfun$apply$1.apply(Play.scala:79)
play.utils.Threads$.withContextClassLoader(Threads.scala:18)
play.api.Play$$anonfun$stop$1.apply(Play.scala:78)
play.api.Play$$anonfun$stop$1.apply(Play.scala:77)
scala.Option.map(Option.scala:145)
play.api.Play$.stop(Play.scala:77)
play.api.test.Helpers$.running(Helpers.scala:42)
test.ApplicationSpec$$anonfun$1$$anonfun$apply$7.apply(ApplicationSpec.scala:24)
Hi,
With "play.api.db.slick.DB" import, we can't use threadLocalSession .
Example :
With
import play.api.db.slick.DB
import scala.slick.session.Database.threadLocalSession
DB.withSession {
Todos.insert("test", "a test")
val q = for {
t <- Todos
} yield (t.name, t.desc)
We have this error :
Overloaded method value [withSession] cannot be applied to (...)
(*)
But this way it's working :
import play.api.db.DB
import scala.slick.session.Database
import scala.slick.session.Database.threadLocalSession
lazy val database = Database.forDataSource(DB.getDataSource())
DB.withSession {
....
}
threadLocalSession is cool because il allows to write
DB.withSession {
...
}
instead of
DB.withSession { implicit session =>
...
}
It can be useful to reduce verbosity if we have a lot of "DB.withSession " blocks
(*) Unit in this case but coud be any type
Hi @freekh
I will try to improve the documentation of the plugin.
Do you think it would be ok to add a part with "default configuration datasource" , i.e. using directly the import from the Config object, in addition to the multi driver/cake pattern section?
I will also add some parts about the way to test the app with a test datasource.
Thanks
Loïc
Hey,
I made a little example a few weeks ago on how to integrate Slick with Play2. My example uses Cake Pattern and driver configuration via application.conf of Play, so that when you create a Table class, you don't have to create this for a certain Slick driver, but you can create this for any, and then you can configure this in the application.conf
Take a look at https://github.com/mgonto/slick-play2-example specifically https://github.com/mgonto/slick-play2-example/blob/master/app/models/DBeable.scala and let me know if you want to include this to the plugin. I can give you a hand on doing so.
I might be missing something, but I'm getting this error when trying to access an Oracle database using the slick-extensions. (The ojdbc14.jar
files in the lib directory.)
play.api.Configuration$$anon$1: Configuration error[Slick error : Unknown jdbc driver found in application.conf: [oracle.jdbc.driver.OracleDriver]]
Several problems need to be fixed around DBAction :
SimpleResult
and Action.async
to avoid Play 2.2 warnings[warn] play-slick/src/main/scala/play/api/db/slick/package.scala:42: trait Result in package mvc is deprecated: Result will become SimpleResult in Play 2.3
[warn] def apply(r: (RequestWithDbSession) => Result)(implicit app:Application) = {
[warn] ^
[warn] play-slick/src/main/scala/play/api/db/slick/package.scala:44: class AsyncResult in package mvc is deprecated: Use Future[SimpleResult] with Action.async action builder instead. Will be removed in Play 2.3.
[warn] AsyncResult {
Future should wrap all the action/session : http://stackoverflow.com/questions/18579684/play-slick-and-async-is-it-a-race-condition
DBAction should be able to take a database name parameter (see #78)
Like this:
slick.default.driver=scala.slick.H2Driver
This will scala.slick.H2Driver independent on what the url can read.
The reason we want something like this is to be able to make sure we support all slick drivers (even selfmade)
Currently, the doc is not explicit about the benefits of DDL creation. Should also specify in which uses cases you should not use DDL creation.
The SlickDDLPlugin should be changed to discover classes from packages, so that the recommended usage of Slick is supported, where you define table objects like this:
val SomeTable = new SomeTable
class SomeTable extends Table[ ... ]
If the plugin is activated but does not find anything it should fail visibly to avoid silent reusing of outdated evolution scripts.
Additionally we should document the purpose of the plugin, i.e. that is only meant for rapid prototyping and getting started, not for longer term development.
The correct class should be
db.default.driver=com.mysql.jdbc.Driver
but the Config seems to expect "com.mysql.Driver" for mysql and since I also use anorm there is a conflict where or anorm (correctly) or slick complains about the driver.
You might also want to update the error message as below, currently the user has to browse the source to find out what is supported:
java.lang.RuntimeException: Unknown driver [valueenteredinconfig], supported drivers are [x, y, z, ...]
I'am looking for Query() function in a sample like "Query(Cats) where _.name=="kitty" ".
See comments on the pull request here : playframework/playframework#1230
Hey folks,
I was getting a compile error "not found: value DBAction" when trying to migrate my anorm-based sample project to slick. At first I assumed I'd made a configuration error, so I tried again, this time using a fresh checkout of computer-database sample.
The computer-database project works fine without any changes, however when the Build.scala is altered to remove the dependency on the RootProject and "com.typesafe.play" %% "play-slick" % "0.3.3" added instead as an appDependency, I get the same compile error.
Most likely a newbie error, but perhaps someone wiser than me may be able to help..
Many thanks,
-dan
I am use play + play-slick-0.3.2 + slick 1.0.0
add import play.api.db.slick.Config.driver.simple._
I write follow statement to delete one db record:
EmpDepartments.where(ed => (ed.empId is it) && ed.endDate.isNull).delete
the compiler say:
value delete is
not a member of scala.slick.lifted.Query[models.EmpDepartments.type,scala.slick
.lifted.NothingContainer#TableNothing]
when I change to
Query(EmpDepartments.where(ed => (ed.empId is it) && ed.endDate.isNull)).delete
compile error change to:
Don't know how
to unpack scala.slick.lifted.Query[models.EmpDepartments.type,scala.slick.lifted
.NothingContainer#TableNothing] to U and pack to R
Very strange, sometimes compile is ok and run result also ok. finally, i replace it with NativeQuery, I really like scala style query or update, i don't know this is a issue about play-slick or slick even or scala.
This plugin worked great with MySQL, but the change to MSSQL(with jtds) broke my application. I now get a [RuntimeException: java.lang.ExceptionInInitializerError]
whenever I try to access my db. The bottom of my stack trace says
Caused by: play.api.Configuration$$anon$1: Configuration error[Slick error : Unknown jdbc driver found in application.conf: [net.sourceforge.jtds.jdbc.Driver]]
at play.api.Configuration$.play$api$Configuration$$configError(Configuration.scala:80) ~[play_2.10.jar:2.1.1]
at play.api.Configuration.reportError(Configuration.scala:558) ~[play_2.10.jar:2.1.1]
at play.api.db.slick.Config$.driver(Config.scala:21) ~[play-slick_2.10-0.3.3.jar:0.3.3]
at play.api.db.slick.Config$.driver$lzycompute(Config.scala:7) ~[play-slick_2.10-0.3.3.jar:0.3.3]
at play.api.db.slick.Config$.driver(Config.scala:7) ~[play-slick_2.10-0.3.3.jar:0.3.3]
Using version 0.3.3 of the plugin.
More info here
I'm trying to use play-slick over slick-extenions' Oracle support to no avail... apparently a reference to oracle.jdbc.OracleDriver is needed in the hard-coded map play.api.db.slick.Database.driverByName of jdbc driver's class name to slick driver. ¿Really?...
To preface, this is probably a mistake on my part.
I'm using com.microsoft.sqlserver.jdbc.SQLServerDriver. Just as a test I created a brand new empty database, and I have only one mapped Object in my models package. When I attempt to access the application, I get the expected error Database 'default' needs evolution!
, and the proper evolution sql is generated. When I click Apply this script now!
, the play_evolutions table is created, but the evolution itself doesn't actually get applied. A table should be created, but it is not, and there are no entries in the play_evolutions table. Consequently, the error page Database 'default' needs evolution!
continues to display on refresh.
I verified that the user indeed had the proper privileges to create the table by running the sql as that user in my SQL Server Management Studio, and it went off without a hitch. There are no other errors in the console/logs (just the one about the evolution needing to be applied).
Any thoughts? Are there known issues with the microsoft jdbc driver? As an aside, I would prefer to use jTDS but it doesn't look like it's supported by play-slick. Is there any plan to add support for jtds?
Thanks.
This plugin seems very interesting.
Do you have a sample app using it?
It would be cool to have some examples, especially about (multi) driver management.
Thanks
The Slick documentation should be clearer on this, but having singleton objects in static locations extend Table[...] is buggy. This is done e.g. in https://github.com/freekh/play-slick/blob/f513fdab1031de3991689afa334d175411484c78/samples/play-slick-sample/app/models/Cat.scala . It works if you do not use certain Slick features, but it does not work in the general case, because Slick clones the object under the hood and then stumbles over https://issues.scala-lang.org/browse/SI-3764 if they are defined in a static location. Instead we recommend either putting them in a trait or class or using the pattern
val SomeTable = new SomeTable
class SomeTable extends Table[ ... ]
The SlickDDLPlugin does not work with the val version, as it assumes static objects. Even worse, it did not tell me it does not support this when I switched from object to val, but just re-used the old sql-script under the hood. This lead me to committing broken versions until I changed the tables in an incompatible way that lead to exceptions in certain queries.
The SlickDDLPlugin could be fixed in these regards, but I propose a more radical change. In my opinion the reflection based table object discovery the SlickDDLPlugin does is too magical, hard to explain, debug and get right. How about using an ordinary Scala interface instead? Like a method you call, which you give a Seq of table objects? Then we could remove all the reflection magic I suppose.
I have migrated my DB access to use slick. However the DDL generated is inconsistent for my models package : each time I access the application via a browser, it wants to apply an DDL update to change the order in which the tables are created.
The application is completely unusable now !
The code to reproduce the issue (only the models) is in this public gist : https://gist.github.com/tyrcho/5086544
I get play.api.UnexpectedException: Unexpected exception[ExceptionInInitializerError: null]
after play new
, adding slick.default="models.*"
to application.conf and creating the model:
package models
import play.api.db.slick.Config.driver._
case class Cat(name: String, color: String)
object Cats extends Table[Cat]("CAT") {
def name = column[String]("name", O.PrimaryKey)
def color = column[String]("color", O.NotNull)
def * = name ~ color <> (Cat.apply _, Cat.unapply _)
}
Now the default execution context is:
play.api.libs.concurrent.Execution.defaultContext
it should be an execution context with more parallelism.
Slick explicitly states that you should not use a static location for your Table
definitions:
Also make sure that an actual object for a table is not defined in a static location (i.e. at the top level or nested only inside other objects) because this can cause problems in certain situations due to an overeager optimization performed by scalac. Using a val for your table (with an anonymous structural type or a separate class definition) is fine everywhere.
However, play-slick seems only to recognise Table definitions is they are defined statically - trying to define them through a val in a package object results in the following:
ReflectError: value ParameterTypes is not a package
Hi
I'm using play-slick in my Play application.
When running test, my test configuration does not work.
Could you tell me how to fix the problem or could you add some tests specified to use test database into sample app?
application.conf
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.user=sa
db.default.password=""
test.db.default.driver=com.mysql.jdbc.Driver
test.db.default.url="jdbc:mysql://localhost/play_test"
test.db.default.user=test_user
test.db.default.password=test_user_pass
SlickTest
import org.specs2.mutable.Specification
import play.api.test.Helpers._
import play.api.test.FakeApplication
import play.api.db.slick.Config.driver.simple._
import play.api.db.slick.DB
import models.{Cat, Cats}
class SlickSpec extends Specification {
// This test should pass, but uses `db.default.driver`
// How can I use `test.db.default` ?
"Slick" should {
"insert object into test database" in {
running(FakeApplication()) {
import play.api.Play.current
DB.withSession { implicit session =>
val cat = Cat("name", "color")
Cats.insert(cat)
}
DB.withSession { implicit session =>
val count = Query((for (c <- Query(Cats)) yield c.id).countDistinct).first
count must beEqualTo(1)
}
}
}
}
}
Branched off from #33
PlayFramework team has released 2.2.0-M1. It is time to support it.
I have added typesafe repo event then it is throwing error.. using play 2.1.1, sbt 0.12.2 scala 2.10.
[warn] module not found: com.typesafe.play#play-slick;0.3.2
[warn] ==== Typesafe Releases Repository: tried
[warn] http://repo.typesafe.com/typesafe/releases/com/typesafe/play/play-slick/0.3.2/play-slick-0.3.2.pom
[warn] ==== Typesafe Snapshots Repository: tried
[warn] http://repo.typesafe.com/typesafe/snapshots/com/typesafe/play/play-slick/0.3.2/play-slick-0.3.2.pom
[warn] ==== public: tried
[warn] http://repo1.maven.org/maven2/com/typesafe/play/play-slick/0.3.2/play-slick-0.3.2.pom
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: com.typesafe.play#play-slick;0.3.1: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
sbt.ResolveException: unresolved dependency: com.typesafe.play#play-slick;0.3.2: not found
I get following not resolved dependency:
[warn] ==== github repo for play-slick: tried
Shortened Build.sbt is:
import sbt._
import Keys._
import PlayProject._
object ApplicationBuild extends Build {
val appName = "platform"
val appVersion = "1.0"
val appDependencies = Seq(
javaJdbc,
"postgresql" % "postgresql" % "9.1-901-1.jdbc4",
"com.typesafe.slick" % "slick_2.10" % "1.0.0",
"com.typesafe" % "play-slick_2.10" % "0.3.0")
val main = play.Project(appName, appVersion, appDependencies).settings(
resolvers := Seq(
Resolver.url("github repo for play-slick", url("http://loicdescotte.github.com/releases/")))
}
for example:
object SomeDb {
import play.api.db.slick.DB
val db = DB.database("some")
// db.driver() will return the driver for the db.defult, not db.some
val dao = new SomeDAO(db.driver(play.api.Play.current))
}
This is somewhat unexpected and makes it hard to connect to different databases from the same application, when using the pattern described in the README to keep the code independent of the actual drivers.
I'm guessing that this could be fixed by adding a name parameter to Config.driver(app) and passing DB.CurrentDB to the method. Should I send a pull request with this change?
If tests are run multiple times using the DB wrapper, this type of error will start happening:
[error] c.j.b.h.AbstractConnectionHook - Failed to acquire connection Sleeping for 1000ms and trying again. Attempts left: 1. Exception: null
[error] c.j.b.ConnectionHandle - Database access problem. Killing off all remaining connections in the connection pool. SQL State = 08001
I believe it is linked to the way DataSources are created in Play and in Slick.
For a cleaner model, I think I will try to just wrap a Session in the connection from the Play DataSource directly
IMHO, the docs should explain only play-slick specifics like DBAction with Request and Session. For everything about Slick in general we should reference the Slick docs. This includes patterns for common use cases like cake, query libraries, daos, etc.
The latest stable release of this plugin is 0.3.3, yet all the cool DBAction
stuff seems to be happening in master. Would it be possible to get a snapshot release somewhere, or is it perhaps already available? (didn't see where from the build.sbt
definition)
The Slick documentation should be clearer on this, but having singleton objects in static locations extend Table[...] is buggy. This is done e.g. in https://github.com/freekh/play-slick/blob/f513fdab1031de3991689afa334d175411484c78/samples/play-slick-sample/app/models/Cat.scala . It works if you do not use certain Slick features, but it does not work in the general case, because Slick clones the object under the hood and then stumbles over https://issues.scala-lang.org/browse/SI-3764 if they are defined in a static location. Instead we recommend either putting them in a trait or class or using the pattern
val SomeTable = new SomeTable
class SomeTable extends Table[ ... ]
It could be fixed along the lines of cvogt@74899b4
similar to #15 but I have a different error message
Action { request =>
play.api.db.slick.DB.withSession{ implicit session =>
Logger.info(slick.session.Database.threadLocalSession.toString)
Ok
}
}
this gives me:
SQLException: No implicit session available; threadLocalSession can only be used within a withSession block
Am I missing something or is this a bug?
When using log4jdbc in order to log SQL queries, you have to change the driver to the log4jdbc proxy : net.sf.log4jdbc.DriverSpy
. That driver isn't recognized by the extension and thus crashes.
The goal is to have a bigger and more "real world application" sample.
If I have a lazy val and try to use it like this:
class DAO(override val profile: ExtendedProfile) extends CatComponent with Profile
object current {
lazy val dao = new DAO(slick.driver.H2Driver)
}
application.conf
looks like this: slick.default="models.current.dao.*"
The instructions in the current (43c4e55) README.md do not work with Play 2.1.1, sbt 0.12.2 and Scala 2.10.0
The dependency is not found.
I have a controller for POST method. When DBAction
is used, the request.body
is not accessible. The error goes away when i switch to the normal Action
value body is not a member of play.api.db.slick.RequestWithDbSession
[error] request.body.asJson.map { json =>
[error] ^
The relevant code snippet is
def submit = DBAction { implicit request=>
request.body.asJson.map {...}
}
I could reproduce this issue in the computer-database sample app, by adding rs.body
in the Application::Update
action
Could you update the project to use Slick 1.0.1? Thanks!
When I create a project and follow the directions to add a dependency of play-slick via .dependsOn(RootProject( uri("git://github.com/freekh/play-slick.git") ))
and then I run eclipse
to create an eclipse project, there are a few issues.
First, the eclipse
command says that it created eclipse project files for my project and for the play-slick
project, as well. However, when I import the project into Eclipse it only finds the project files for my project, not for the play-eclipse
project, so it complains that there are errors in the build path. If I remove the reference to the play-slick
project in the build path, that error is resolved but a different error remains: The project cannot be built until build path errors are resolved
.
I am using scala-ide with Eclipse Juno. Is there some simple configuration step I'm missing to get a play-slick project imported into Eclipse correctly? Or is there a different method that I should be using to import my project into Eclipse? With other dependencies I simply add maven artifacts to the Build.scala and everything works beautifully. When play-slick has matured, will it be available via the Maven repo, also?
I should mention this is purely an issue for Eclipse. The project itself runs fine (except for the issue I wrote about in my other pull request).
As mentioned here there should be a published jar: #34
@loicdescotte is nice enough to host it for now, but going forward we should avoid to require an extra resolver
Continued from discussion on: slick/slick#158
Looks like play-slick is being used without having a started Play application.
Typically this will not happen unless you are using are calling play-slick:
http://www.playframework.com/documentation/2.1.1/ScalaTest
DB.withSession
...NOTE: I will be on vacation (offline) soon.
The object class DBAction (https://github.com/freekh/play-slick/blob/2.2/src/main/scala/play/api/db/slick/package.scala#L32) uses DB.withSession. DB is a function which is new Database("default",app).
Hi
After upgrading our project to the just released play 2.1.0 version our build is broken due to this plugins dependency on play-2.1-RC4
Thanks
Steffen
play-slick only creates an evolutions file for you if you don't have one yet. That's what you want when you first create your model, but doesn't allow you to use this feature when you later change your model and need to create a 2.sql
, perhaps with a new table.
Suggestion: instead of generating 1.sql
if it isn't there, generate create.sql
and drop.sql
unless a configuration parameter is set to false
. Then you can write your 2.sql
based on the diff between 1.sql
and create.sql
.
I can also imagine situations on a project where you want to run the whole create or drop script on a test database.
As described in this post from sadek, we could define a SlickExecutionContext and a SlickAction to avoid blocking in default thread pool.
Then it could be easier to integrate with other modules that use async/non blocking stuffs, like https://github.com/mandubian/play-autosource
@freekh , if you're OK with the idea I will implement it ASAP :)
Loïc
Great work making Slick work on Play. However, I think I've spotted an easy fix.
It appears that the jar file that is downloaded when you add the dependency to the build.scala file is missing a few classes.
If download the latest from GitHub I can see the package
play.api.db.slick
However, if I inspect the jar that is downloaded when I run eclipse (using the eclipse command) I see the following jar and package:
play-slick_2.10-0.3.3.jar
play.api.db.slick
Hence, I get compile errors when I try and use the session class from within my app. This error doesn't happen in the sample. app that doesn't use the remote dependency.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.