Skip to content
Permalink
Browse files

Fixes for slick-extensions

- shorted column names in tests to <= 30 for Oracle
- remove default schema PUBLIC for H2(?)
- accept integer or char 1 and 0 for mapped non-native booleans
- special case integer and date tests to include oracle (should may be handled via a capability at some later point in time)
- introduces rawDefault method to allow preprocessing the default value meta data (for simplicity in slick-extensions)
  • Loading branch information
cvogt committed Jul 19, 2014
1 parent 5336ceb commit 7baf4070ffbc0ac0f6757313eb4145de25f85b01
@@ -42,9 +42,9 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {
def someStringDefaultNonEmpty = column[String]("some_string_default_non_empty",O.Default("bar"))
def someStringDefaultEmpty = column[String]("some_string_default_empty",O.Default(""))
def someStringOption = column[Option[String]]("some_string_option")
def someStringOptionDefaultEmpty = column[Option[String]]("some_string_option_default_empty",O.Default(Some("")))
def someStringOptionDefaultNone = column[Option[String]]("some_string_option_default_none",O.Default(None))
def someStringOptionDefaultNonEmpty = column[Option[String]]("some_string_option_default_non_empty",O.Default(Some("foo")))
def someStringOptionDefaultEmpty = column[Option[String]]("str_option_default_empty",O.Default(Some("")))
def someStringOptionDefaultNone = column[Option[String]]("str_option_default_none",O.Default(None))
def someStringOptionDefaultNonEmpty = column[Option[String]]("str_option_default_non_empty",O.Default(Some("foo")))
def * = (someBool,someBoolDefaultTrue,someBoolDefaultFalse,someBoolOption,someBoolOptionDefaultSome,someBoolOptionDefaultNone,someString,someStringDefaultNonEmpty,someStringDefaultEmpty,someStringOption,someStringOptionDefaultEmpty,someStringOptionDefaultNonEmpty,someStringOptionDefaultNone)
}
val defaultTest = TableQuery[DefaultTest]
@@ -148,6 +148,7 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {

// check that the model matches the table classes
val model = tdb.profile.createModel(ignoreInvalidDefaults=false)
//println(model)
assertEquals( model.tables.toString, 5, model.tables.size )
;{
val categories = model.tables.filter(_.name.table.toUpperCase=="CATEGORIES").head
@@ -218,7 +219,7 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {
}
};{
val defaultTest = model.tables.filter(_.name.table.toUpperCase=="DEFAULT_TEST").head
assertEquals(None,defaultTest.name.schema)
assert(Some("PUBLIC") != defaultTest.name.schema.map(_.toUpperCase))
assert(Some("PUBLIC") != defaultTest.name.catalog.map(_.toUpperCase))
ifCap(jcap.defaultValueMetaData){
def column(name: String)
@@ -232,13 +233,18 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {
assertEquals(Some(true), columnDefault("some_bool_default_true"))
}
ifNotCap(jcap.booleanMetaData){
assertEquals(Some(1), columnDefault("some_bool_default_true"))
assertEquals(false,column("some_bool_default_true").nullable)
assert( Seq(Some(1),Some('1')).contains(
columnDefault("some_bool_default_true")
), columnDefault("some_bool_default_true").toString )
}
ifCap(jcap.booleanMetaData){
assertEquals(Some(false), columnDefault("some_bool_default_false"))
}
ifNotCap(jcap.booleanMetaData){
assertEquals(Some(0), columnDefault("some_bool_default_false"))
assert( Seq(Some(0),Some('0')).contains(
columnDefault("some_bool_default_false")
), columnDefault("some_bool_default_false").toString )
}
ifCap(jcap.nullableNoDefault){
assertEquals(None,columnDefault("some_bool_option"))
@@ -250,7 +256,9 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {
assertEquals(Some(Some(true)), columnDefault("some_bool_option_default_some"))
}
ifNotCap(jcap.booleanMetaData){
assertEquals(Some(Some(1)), columnDefault("some_bool_option_default_some"))
assert( Seq(Some(Some(1)),Some(Some('1'))).contains(
columnDefault("some_bool_option_default_some")
), columnDefault("some_bool_option_default_some").toString )
}
assertEquals(Some(None),columnDefault("some_bool_option_default_none"))
assertEquals(None,columnDefault("some_string"))
@@ -262,9 +270,9 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {
ifNotCap(jcap.nullableNoDefault){
assertEquals(Some(None),columnDefault("some_string_option"))
}
assertEquals(Some(Some("")),columnDefault("some_string_option_default_empty"))
assertEquals(Some(None),columnDefault("some_string_option_default_none"))
assertEquals(Some(Some("foo")),columnDefault("some_string_option_default_non_empty"))
assertEquals(Some(Some("")),columnDefault("str_option_default_empty"))
assertEquals(Some(None),columnDefault("str_option_default_none"))
assertEquals(Some(Some("foo")),columnDefault("str_option_default_non_empty"))
}
};{
val typeTest = model.tables.filter(_.name.table.toUpperCase=="TYPE_TEST").head
@@ -296,32 +304,32 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {
assertEquals(false,column("Short").nullable)
assertEquals(true,column("Option_Short").nullable)

assertEquals("Int",column("Int").tpe)
assertEquals("Int",column("Option_Int").tpe)
assertEquals(false,column("Int").nullable)
assertEquals(true,column("Option_Int").nullable)
ifCap(jcap.defaultValueMetaData){
assertEquals(Some(-5), columnDefault("Int"))
assertEquals(Some(Some(5)), columnDefault("Option_Int"))
}

ifCap(jcap.distinguishesIntTypes){
assertEquals("Long",column("Long").tpe)
assertEquals("Long",column("Option_Long").tpe)
}
assertEquals(false,column("Long").nullable)
assertEquals(true,column("Option_Long").nullable)
ifCap(jcap.defaultValueMetaData){
assertEquals(Some(5L), columnDefault("Long"))
assertEquals(Some(Some(-5L)), columnDefault("Option_Long"))
if(!tdb.profile.toString.contains("OracleDriver")){// FIXME: we should probably solve this somewhat cleaner
assertEquals("Int",column("Int").tpe)
assertEquals("Int",column("Option_Int").tpe)
ifCap(jcap.defaultValueMetaData){
assertEquals(Some(-5), columnDefault("Int"))
assertEquals(Some(Some(5)), columnDefault("Option_Int"))
}
ifCap(jcap.distinguishesIntTypes){
assertEquals("Long",column("Long").tpe)
assertEquals("Long",column("Option_Long").tpe)
}
ifCap(jcap.defaultValueMetaData){
assertEquals(Some(5L), columnDefault("Long"))
assertEquals(Some(Some(-5L)), columnDefault("Option_Long"))
}
}
/* h2 and hsqldb map this to Double
assertEquals("Float",column("Float").tpe)
assertEquals("Float",column("Option_Float").tpe)
assertEquals(false,column("Float").nullable)
assertEquals(true,column("Option_Float").nullable)
*/
println(column("java_sql_Blob"))
assertEquals("Double",column("Double").tpe)
assertEquals("Double",column("Option_Double").tpe)
assertEquals(false,column("Double").nullable)
@@ -332,21 +340,22 @@ class MetaModelTest extends TestkitTest[JdbcTestDB] {
assertEquals(false,column("String").nullable)
assertEquals(true,column("Option_String").nullable)

assertEquals("java.sql.Date",column("java_sql_Date").tpe)
assertEquals("java.sql.Date",column("Option_java_sql_Date").tpe)
assertEquals(false,column("java_sql_Date").nullable)
assertEquals(true,column("Option_java_sql_Date").nullable)

assertEquals("java.sql.Time",column("java_sql_Time").tpe)
assertEquals("java.sql.Time",column("Option_java_sql_Time").tpe)
assertEquals(false,column("java_sql_Time").nullable)
assertEquals(true,column("Option_java_sql_Time").nullable)

assertEquals("java.sql.Timestamp",column("java_sql_Timestamp").tpe)
assertEquals("java.sql.Timestamp",column("Option_java_sql_Timestamp").tpe)
assertEquals(false,column("java_sql_Timestamp").nullable)
assertEquals(true,column("Option_java_sql_Timestamp").nullable)

if(!tdb.profile.toString.contains("OracleDriver")){// FIXME: we should probably solve this somewhat cleaner
assertEquals("java.sql.Date",column("java_sql_Date").tpe)
assertEquals("java.sql.Date",column("Option_java_sql_Date").tpe)
assertEquals("java.sql.Time",column("java_sql_Time").tpe)
assertEquals("java.sql.Time",column("Option_java_sql_Time").tpe)
assertEquals("java.sql.Timestamp",column("java_sql_Timestamp").tpe)
assertEquals("java.sql.Timestamp",column("Option_java_sql_Timestamp").tpe)
}

assertEquals("java.sql.Blob",column("java_sql_Blob").tpe)
assertEquals("java.sql.Blob",column("Option_java_sql_Blob").tpe)
assertEquals(false,column("java_sql_Blob").nullable)
@@ -174,6 +174,8 @@ trait JdbcModelComponent{ driver: JdbcDriver =>
java.sql.Types.LONGNVARCHAR
) contains meta.sqlType

def rawDefault = meta.columnDef

/** The default value for the column.
* The outer option is used to indicate if a default value is given.
* The inner Option is used to allow giving None for a nullable column.
@@ -187,7 +189,7 @@ trait JdbcModelComponent{ driver: JdbcDriver =>
*/

def default: Option[Option[Any]]
= meta.columnDef.map{ v =>
= rawDefault.map{ v =>
if(v=="NULL"){
None
} else {
@@ -198,8 +200,10 @@ trait JdbcModelComponent{ driver: JdbcDriver =>
case (v,"Int") => v.toInt
case (v,"Long") => v.toLong
case (v,"Double") => v.toDouble
case (v,"Float") => v.toFloat
case (v,"Char") => v.head // FIXME: check length
case (v,"Float") => v.toFloat
case (v,"Char") =>
assert(v.size == 1, "char has unexpected size: "+v)
v.head
case (v,"String") if meta.typeName == "CHAR" => v.head // FIXME: check length
case (v,"scala.math.BigDecimal") => v // FIXME: probably we shouldn't use a string here
case (StringPattern(str),"String") => str
@@ -223,7 +227,7 @@ trait JdbcModelComponent{ driver: JdbcDriver =>
* logs the message and treats it as no default value for convenience.
*/
def defaultColumnOption: Option[ColumnOption.Default[_]]
= meta.columnDef.map(v => (v,tpe)).collect{
= rawDefault.map(v => (v,tpe)).collect{
case (v@"CURRENT_TIMESTAMP","java.sql.Timestamp") =>
logger.debug(s"Ignoring"+formatDefault(v))
None
@@ -243,11 +247,11 @@ trait JdbcModelComponent{ driver: JdbcDriver =>
case e: java.lang.NumberFormatException
if ignoreInvalidDefaults =>
logger.debug(
s"NumberFormatException: Could not parse"+formatDefault(meta.columnDef)
s"NumberFormatException: Could not parse"+formatDefault(defaultColumnOption)
)
None
case e: scala.MatchError =>
val msg = s"Could not parse"+formatDefault(meta.columnDef)
val msg = s"Could not parse"+formatDefault(defaultColumnOption)
if(ignoreInvalidDefaults){
logger.debug("SlickException: "+msg)
None
@@ -30,9 +30,8 @@ import scala.slick.model.Model
* just as specifying NULL and reports NULL as the default value.
* Some other dbms treat queries with no default as NULL default, but
* distinguish NULL from no default value in the meta data.</li>
* <li>[[scala.slick.driver.JdbcProfile.capabilities.supportsByte]]:
* Derby doesn't have a corresponding type for Byte.
* Postgres doesn't have a corresponding type for Byte.
* SMALLINT is used instead and mapped to Short in the Slick model.</li>
* </ul>
*
@@ -55,9 +55,9 @@ import scala.slick.jdbc.meta.MTable
* Also see https://code.google.com/p/sqlite-jdbc/issues/detail?id=27
* </li>
* <li>[[scala.slick.driver.JdbcProfile.capabilities.booleanMetaData]]:
* Derby <= 10.6 doesn't have booleans, so Slick maps to SMALLINT instead.
* SQlite doesn't have booleans, so Slick maps to INTEGER instead.
* Other jdbc drivers like MySQL map TINYINT(1) back to a Scala
* Boolean. Derby maps SMALLINT to an Integer and that's how it shows
* Boolean. SQlite maps INTEGER to an Integer and that's how it shows
* up in the jdbc meta data, thus the original type is lost.</li>
* <li>[[scala.slick.driver.JdbcProfile.capabilities.distinguishesIntTypes]]:
* SQLite does not distinguish integer types and maps them all to Int

0 comments on commit 7baf407

Please sign in to comment.
You can’t perform that action at this time.