Permalink
Browse files

Fix default value generation for postgresql columns include #1123, te…

…stcase.
  • Loading branch information...
AtkinsChang committed Jul 31, 2016
1 parent 8dcb5e3 commit d11238e88d752042dae8dd81572c6288ca3ae8ab
@@ -170,6 +170,7 @@ class $name(_tableTag: Tag) extends profile.api.Table[$elementType](_tableTag, $
}
def defaultCode = {
case Some(v) => s"Some(${defaultCode(v)})"
case v:String if model.tpe == "scala.math.BigDecimal" => s"""new scala.math.BigDecimal(new java.math.BigDecimal("$v"))"""
case s:String => "\""+s+"\""
case None => s"None"
case v:Byte => s"$v"
@@ -180,7 +181,7 @@ class $name(_tableTag: Tag) extends profile.api.Table[$elementType](_tableTag, $
case v:Boolean => s"$v"
case v:Short => s"$v"
case v:Char => s"'$v'"
case v:BigDecimal => s"new scala.math.BigDecimal(new java.math.BigDecimal($v))"
case v:BigDecimal => s"""new scala.math.BigDecimal(new java.math.BigDecimal("$v"))"""
case v => throw new SlickException( s"Dont' know how to generate code for default value $v of ${v.getClass}. Override def defaultCode to render the value." )
}
// Explicit type to allow overloading existing Slick method names.
@@ -0,0 +1,53 @@
DROP TABLE IF EXISTS "test";
CREATE TABLE "test" ("smallint_auto_inc" SMALLSERIAL,
"smallint_no_default" SMALLINT,
"smallint_default_zero" SMALLINT DEFAULT 0,
"smallint_default_pos" SMALLINT DEFAULT 1,
"smallint_default_neg" SMALLINT DEFAULT -1,
"smallint_default_max" SMALLINT DEFAULT 32767,
"smallint_default_min" SMALLINT DEFAULT -32768,
"int_auto_inc" SERIAL,
"int_no_default" INT,
"int_default_zero" INT DEFAULT 0,
"int_default_pos" INT DEFAULT 1,
"int_default_neg" INT DEFAULT -1,
"int_default_max" INT DEFAULT 2147483647,
"int_default_min" INT DEFAULT -2147483648,
"bigint_auto_inc" BIGSERIAL,
"bigint_no_default" BIGINT,
"bigint_default_zero" BIGINT DEFAULT 0,
"bigint_default_pos" BIGINT DEFAULT 1,
"bigint_default_neg" BIGINT DEFAULT -1,
"bigint_default_max" BIGINT DEFAULT 9223372036854775807,
"bigint_default_min" BIGINT DEFAULT -9223372036854775808,
"real_no_default" REAL,
"real_default_int_zero" REAL DEFAULT 0,
"real_default_int_pos" REAL DEFAULT 1,
"real_default_int_neg" REAL DEFAULT -1,
"real_default_int_pos2" REAL DEFAULT 9223372036854775807,
"real_default_int_neg2" REAL DEFAULT -9223372036854775808,
"real_default_zero" REAL DEFAULT 0.0,
"real_default_pos" REAL DEFAULT 1.1,
"real_default_neg" REAL DEFAULT -1.1,
"double_precision_no_default" DOUBLE PRECISION,
"double_precision_default_int_zero" DOUBLE PRECISION DEFAULT 0,
"double_precision_default_int_pos" DOUBLE PRECISION DEFAULT 1,
"double_precision_default_int_neg" DOUBLE PRECISION DEFAULT -1,
"double_precision_default_int_pos2" DOUBLE PRECISION DEFAULT 9223372036854775807,
"double_precision_default_int_neg2" DOUBLE PRECISION DEFAULT -9223372036854775808,
"double_precision_default_zero" DOUBLE PRECISION DEFAULT 0.0,
"double_precision_default_pos" DOUBLE PRECISION DEFAULT 1.1,
"double_precision_default_neg" DOUBLE PRECISION DEFAULT -1.1,
"numeric_no_default" NUMERIC,
"numeric_default_int_zero" NUMERIC DEFAULT 0,
"numeric_default_int_pos" NUMERIC DEFAULT 1,
"numeric_default_int_neg" NUMERIC DEFAULT -1,
"numeric_default_int_pos2" NUMERIC DEFAULT 9223372036854775807,
"numeric_default_int_neg2" NUMERIC DEFAULT -9223372036854775808,
"numeric_default_zero" NUMERIC DEFAULT 0.0,
"numeric_default_pos" NUMERIC DEFAULT 1.1,
"numeric_default_neg" NUMERIC DEFAULT -1.1,
"char_dafault" CHAR(5) DEFAULT 'abcde',
"varchar_default" VARCHAR DEFAULT 'abcde',
"text_default" TEXT DEFAULT 'abcde'
);
@@ -104,6 +104,7 @@ val SimpleA = CustomTyping.SimpleA
""".stripMargin
},
new UUIDConfig("Postgres2", StandardTestDBs.Postgres, "Postgres", Seq("/dbs/uuid-postgres.sql")),
new Config("Postgres3", StandardTestDBs.Postgres, "Postgres", Seq("/dbs/postgres.sql")),
new Config("EmptyDB", StandardTestDBs.H2Mem, "H2Mem", Nil),
new Config("Oracle1", StandardTestDBs.Oracle, "Oracle", Seq("/dbs/oracle1.sql")) {
override def useSingleLineStatements = true
@@ -97,7 +97,7 @@ trait TestCodeGenerator {
| import scala.concurrent.ExecutionContext.Implicits.global
| $testCode
|}
""".stripMargin + super.code
|""".stripMargin + super.code
}
}
}
@@ -1,12 +1,13 @@
package slick.test.codegen
import scala.concurrent.ExecutionContext.Implicits.global
import slick.ast.{Node, Select}
import slick.ast.{FieldSymbol, Node, Select}
import slick.jdbc.JdbcProfile
import slick.jdbc.meta.MTable
import slick.test.codegen.generated._
import com.typesafe.slick.testkit.util.{TestCodeRunner, JdbcTestDB}
import org.junit.Assert._
import slick.relational.RelationalProfile
/** Test files generated by CodeGeneratorTest */
class GeneratedCodeTest extends TestCodeRunner(AllTests)
@@ -50,7 +51,7 @@ object GeneratedCodeTest {
assertTrue("Indices should refer to correct field", dIdxFieldsName sameElements List("f1", "f2"))
def optionsOfColumn(c: slick.lifted.Rep[_]) =
c.toNode.asInstanceOf[Select].field.asInstanceOf[slick.ast.FieldSymbol].options.toList
c.toNode.asInstanceOf[Select].field.asInstanceOf[FieldSymbol].options.toList
val k1Options = optionsOfColumn(E.baseTableRow.k1)
val k2Options = optionsOfColumn(E.baseTableRow.k2)
val sOptions = optionsOfColumn(E.baseTableRow.s)
@@ -134,6 +135,30 @@ object GeneratedCodeTest {
)
}
def testPostgres3 = {
import Postgres3._
import profile.api._
DBIO.seq(
schema.create,
MTable.getTables(Some(""), Some("public"), None, None).map { tables =>
def optionsOfColumn(c: slick.lifted.Rep[_]) =
c.toNode.asInstanceOf[Select].field.asInstanceOf[FieldSymbol].options.toList
val smallserialOptions = optionsOfColumn(Test.baseTableRow.smallintAutoInc)
val serialOptions = optionsOfColumn(Test.baseTableRow.intAutoInc)
val bigserialOptions = optionsOfColumn(Test.baseTableRow.bigintAutoInc)
val charEmptyOptions = optionsOfColumn(Test.baseTableRow.charDefaultEmpty)
val charValidOptions = optionsOfColumn(Test.baseTableRow.charDefaultValid)
val charInvalidOptions = optionsOfColumn(Test.baseTableRow.charDefaultInvalid)
assertTrue("smallint_auto_inc should be AutoInc", smallserialOptions.exists(option => (option equals Test.baseTableRow.O.AutoInc)))
assertTrue("int_auto_inc should be AutoInc", serialOptions.exists(option => (option equals Test.baseTableRow.O.AutoInc)))
assertTrue("bigint_auto_inc should be AutoInc", bigserialOptions.exists(option => (option equals Test.baseTableRow.O.AutoInc)))
assertTrue("default value of char_default_empty should be ' '", charEmptyOptions.exists(option => (option equals Test.baseTableRow.O.Default(' '))))
assertTrue("default value of char_default_valid should be 'a'", charValidOptions.exists(option => (option equals Test.baseTableRow.O.Default('a'))))
assertTrue("default value of char_default_invalid should not exist", charInvalidOptions.forall(option => (option.isInstanceOf[RelationalProfile.ColumnOption.Default[_]])))
}
)
}
def testEmptyDB = slick.dbio.DBIO.successful(())
def tableName( node:Node ) : String = {
@@ -63,25 +63,27 @@ trait PostgresProfile extends JdbcProfile {
override def schema = super.schema.filter(_ != "public") // remove default schema
}
override def createColumnBuilder(tableBuilder: TableBuilder, meta: MColumn): ColumnBuilder = new ColumnBuilder(tableBuilder, meta) {
val VarCharPattern = "^'(.*)'::character varying$".r
val TextPattern = "^'(.*)'::text".r
val IntPattern = "^\\((-?[0-9]*)\\)$".r
val NumericPattern = "^'(-?[0-9]+.?[0-9]*)'::(?:numeric|bigint|integer)".r
val TextPattern = "^'(.*)'::(?:bpchar|character varying|text)".r
val UUIDPattern = "^'(.*)'::uuid".r
override def default = meta.columnDef.map((_,tpe)).collect{
case ("true","Boolean") => Some(Some(true))
case ("false","Boolean") => Some(Some(false))
case (VarCharPattern(str),"String") => Some(Some(str))
case (TextPattern(str),"String") => Some(Some(str))
case (IntPattern(v),"Int") => Some(Some(v.toInt))
case (IntPattern(v),"Long") => Some(Some(v.toLong))
case ("NULL::character varying","String") => Some(None)
case (v,"java.util.UUID") => {
if (v.matches("^['\"].*['\"](::uuid)?$")) {
val uuid = v.replaceAll("[\'\"]", "") //strip quotes
.stripSuffix("::uuid") //strip suffix
Some(Some(java.util.UUID.fromString(uuid)))
} else
None // The UUID is generated through a function - treat it as if there was no default.
case (TextPattern(str),"Char") => str.length match {
case 0 => Some(Some(' ')) // Default to one space, as the char will be space padded anyway
case 1 => Some(Some(str.head))
case _ => None // This is invalid, so let's not supply any default
}
case (NumericPattern(v),"Short") => Some(Some(v.toShort))
case (NumericPattern(v),"Int") => Some(Some(v.toInt))
case (NumericPattern(v),"Long") => Some(Some(v.toLong))
case (NumericPattern(v),"Float") => Some(Some(v.toFloat))
case (NumericPattern(v),"Double") => Some(Some(v.toDouble))
case (NumericPattern(v), "scala.math.BigDecimal") => Some(Some(v))
case (v, "scala.math.BigDecimal") => Some(Some(v))
case (UUIDPattern(v),"java.util.UUID") => Some(Some(java.util.UUID.fromString(v)))
case (_,"java.util.UUID") => None // The UUID is generated through a function - treat it as if there was no default.
}.getOrElse{
val d = super.default
if(meta.nullable == Some(true) && d == None){

0 comments on commit d11238e

Please sign in to comment.