Remove Identifiers trait
Remove unneeded trait Identifiers. All class from him is not depend on cake classes, so they could be top level.
Hi,
Unfortunately, the fix #15 to remove HasJdbcDriver from Identifiers did not do the trick, because as long as the Identifiers is a trait, even if I implement it with some helper object, the WithId and BaseId traits become incompatible with the classes defining repositories, i.e. I get this error
type arguments [com.example.model.UserId,com.example.model.User] do not conform to class
IdTable's type parameter bounds [Id <: Tables.this.BaseId,Entity <: Tables.this.WithId[Id]]
There is a general problem with the sample usage of Unicorn shown in the README:
import package com.example.Unicorn._
import package com.example.Unicorn.driver.simple._
case class UserId(id: Long) extends AnyVal with BaseId
In order to use BaseId I already need to have a concrete instance of the Unicorn object, but all I am doing is defining a data model, I don't know which JdbcDriver I will end up using.
I think the simplest solution is to remove Identifiers traits and make WithId / BaseId into top level traits.
@javajumbo Resolving this issue could be problematic in terms of unicorn 0.6.x.
We introduce parameter to Unicorn for Underlying type. It's easy to resolve definition of data in this use case. When you want to avoid choosing the driver your implementation of unicorn could be like this
package com.example
import org.virtuslab.unicorn.{HasJdbcDriver, UnicornCore}
import scala.slick.driver.JdbcDriver
object Unicorn extends UnicornCore[Long] with HasJdbcDriver {
override val driver: JdbcDriver = ???
}
using this would be same as using in core examples.
import package com.example.Unicorn._
import package com.example.Unicorn.driver.simple._
case class UserId(id: Long) extends AnyVal with BaseId
Hi - I am not sure if I follow your comment fully, but I've looked at the commits linked to this issue, and they look pretty much along the lines I was expecting, so should solve my issue. I will give it a try by replacing my custom hack with 0.6 version.
@bambuchaAdm
do you guys have a working example of configuring UnicornCore without static driver selection? I used to be able to define my model classes without any cake pattern, simply as
import org.virtuslab.unicorn._
case class UserId(id: Long) extends BaseId
Not it seems even for a simple data model I have to import from an object extending unicorn. In such object I assume I cannot just leave the driver member as ???, can I?
It seems in 0.6.x the cake pattern was extended way more than needed.
We want to make usage of unicorn as simple as possible. The main reason that cake pattern is used in project is that slick use it heavily.
The core example shows how to use unicorn without using cake in project. Right after you define your bake cake
package com.example
import org.virtuslab.unicorn.{HasJdbcDriver, LongUnicornCore}
import scala.slick.driver.H2Driver
object Unicorn extends LongUnicornCore with HasJdbcDriver {
val driver = H2Driver
}
the usage in code is simply as you describe
import package com.example.Unicorn._
import package com.example.Unicorn.driver.simple._
Not it seems even for a simple data model I have to import from an object extending unicorn. In such object I assume I cannot just leave the driver member as ???, can I?
If this solution is temporally, ex. database will be chosen later but still in project) yes, but you will be unable to perform any runtime test (exception on loading class will be thrown. I was tested this scenario on previous response).
Moreover you could make your implementation like this
object ExampleUnicorn
extends LongUnicornCore
with HasJdbcDriver {
override lazy val driver = {
// here load database driver using config and reflection
}
}
Implementation like this is used in play-slick in Config and dynamical choose which config should be used.
So, for development (differed choose of static driver) you could use ??? for driver. For more dynamic solution you could use lazy val.
It seems in 0.6.x the cake pattern was extended way more than needed.
I didn't see other way how to implement parametrization for arbitrary Underlaying type for BaseId and don't brake signature for those class in client code. Unfortunately API has changed but there is easy migration way.
Hm, I think we're back to my original problem. Even with the parametrization, the data model should not need anything more than static imports
import org.virtuslab.unicorn._
case class UserId(id: Long) extends BaseId[Long]
case class PictureId(id: String) extends BaseId[String]
Then when defining the Unicorn class, I wouldn't expect to provide a parameter at the top level, because the business function of the Unicorn class is to wire in the driver implementation. Which ID type to use on the tables is already known when we use the types defined above in the IdTable:
class Pictures(tag: Tag) extends IdTable[PictureId, Picture](tag, "PICTURES")
Here we know that the ID type is String.
The problem I have with the Play pattern is it forces the driver selection too early. Yes, you can delay it by reading it from the config, but it means I need to have a config even to run the unit tests. With 0.5.x (after I hacked it to remove the Identities trait) I simply had a trait SlickTestSupport I needed to mix into the unit test classes, where the DAL object was initialized with the underlying Unicorn object.
trait SlickTestSupport {
val db = SlickTestSupport.database
val dal = SlickTestSupport.dal
}
object TestUnicorn extends LongUnicornCore with HasJdbcDriver {
override val driver = H2Driver
}
object SlickTestSupport extends Logging {
val database = Database.forURL("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")
val dal = {
val dal = new MyDAL {
override lazy val unicorn = TestUnicorn
def db = database
}
try {
dal.createSchema
} catch {
case t: Throwable => {
log.error("Failed to create schema", t)
throw t
}
}
dal
}
}
Then in the real application, I would instantiate MyDAL with a driver loaded based on the configuration and let Spring inject it where needed. As a result, I have data model independent of the driver, all knowledge of Unicorn and Slick is encapsulated inside the MyDAL class.