Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error to generate code with Postgres datatype _uuid or timestamp even with joda datetime support #552

Open
zhangchuanben opened this issue Apr 15, 2022 · 0 comments

Comments

@zhangchuanben
Copy link

zhangchuanben commented Apr 15, 2022

  • Version : 0.20.2
  • Issue Description:
    When i was using Slick's SourceCodeGenerator for Postgres. I found two issues.
  1. When the db field type is timestamp, i've opened Joda Support, however when i finished generate code, i have to manually add code com.github.tototoshi.slick.PostgresJodaSupport._
  2. When the db field type is _uuid, the final generated code is scala.collection.Seq, i think the generated code should be List[java.util.UUID]

It will be grateful if someone can help to explain or fix, i will glad too if you guys need me to provide more details

  • Test table schema
CREATE TABLE public.order_comments (
	id uuid NOT NULL,
	vas_no varchar(16) NOT NULL,
	comment_ts timestamp(3) NOT NULL,
	"comment" varchar(1024) NULL,
	file_ids _uuid NULL,
	photo_ids _uuid NULL,
	status_id varchar(32) NOT NULL,
	comment_person varchar(64) NOT NULL,
	comment_person_id uuid NOT NULL
);
  • Generate Script Code

    CustomSourceCodeGenerator.scala

    package com.code.gen
    import slick.codegen.SourceCodeGenerator
    import slick.model.Model
    
    class CustomSourceCodeGenerator(model: Model)
        extends SourceCodeGenerator(model) {
      override def code =
        "import com.github.tototoshi.slick.PostgresJodaSupport._\n" + "import org.joda.time.DateTime\n" + super.code
      override def Table = new Table(_) {
        override def Column = new Column(_) {
    
          // munge rawType -> SQL column type HERE (scaladoc in Slick 2.1.0 is outdated or incorrect, GeneratorHelpers#mapJdbcTypeString does not exist)
          // you can filter on model.name for the column name or model.tpe for the column type
          // your IDE won't like the String here but don't worry, the return type the compiler expects here is String
          override def rawType = model.tpe match {
    //        case "org.joda.time.LocalDateTime" => "DateTime" // kill j.s.Timestamp
            case _ => {
              println(
                s"${model.table.table}#${model.name} tpe=${model.tpe} rawType=${super.rawType}"
              )
              super.rawType
            }
          }
        }
      }
    }

    GenCode.scala

    package com.code.gen
    import slick.jdbc.JdbcProfile
    import com.ben.MyPostgresProfile.api._
    import scala.concurrent.Await
    import scala.concurrent.ExecutionContext.Implicits._
    import scala.concurrent.duration.Duration
    
    object GenCode extends App {
      val profile =
        "com.ben.MyPostgresProfile" // TODO: replace this with your Slick driver
      val jdbcDriver =
        "org.postgresql.Driver" // TODO: replace this with your JDBC driver
      val url =
        "jdbc:postgresql://127.0.0.1:5433/test" // TODO: replace this with your database's JDBC URL
      val outputFolder =
        "src/main/scala" // TODO: or whatever output folder you're in the mood for
      val pkg = "com.ben1" // TODO: your package name
      val user =
        "postgres" // TODO: database username - optional, use forURL supports both with and without credentials
      val password =
        "" // TODO: database password - optional, use forURL supports both with and without credentials
    
      val driver: JdbcProfile =
        com.ben.MyPostgresProfile // TODO: replace this with your Slick driver
    
      val db = {
        // UNCOMMENT this if your database doesn't need credentials
        // driver.simple.Database.forURL(url, jdbcDriver)
        Database.forURL(
          url,
          driver = jdbcDriver,
          user = user,
          password = password
        )
      }
    
      val modelAction = com.ben.MyPostgresProfile
        .createModel(
          Some(com.ben.MyPostgresProfile.defaultTables)
        )
        .map(model =>
          new CustomSourceCodeGenerator(model).writeToMultipleFiles(
            profile = profile,
            folder = outputFolder,
            pkg = pkg,
            container = "Tables"
          )
        )
      val rs = db.run(modelAction)
      Await.result(rs, Duration.Inf)
    }
  • PGProfile

    MyPostgresProfile.scala

    package com.ben
    
    import com.github.tminglei.slickpg._
    import play.api.libs.json.{JsValue, Json}
    trait MyPostgresProfile
        extends ExPostgresProfile
        with PgArraySupport
    //    with PgDate2Support
        with PgDateSupportJoda
        with PgRangeSupport
        with PgHStoreSupport
        with PgPlayJsonSupport
        with PgSearchSupport
    //    with PgPostGISSupport
        with PgNetSupport
        with PgLTreeSupport {
      def pgjson =
        "jsonb" // jsonb support is in postgres 9.4.0 onward; for 9.3.x use "json"
    
      // Add back `capabilities.insertOrUpdate` to enable native `upsert` support; for postgres 9.5+
      override protected def computeCapabilities: Set[slick.basic.Capability] =
        super.computeCapabilities + slick.jdbc.JdbcCapabilities.insertOrUpdate
    
      override val api = MyAPI
    
      object MyAPI
          extends API
          with ArrayImplicits
          with DateTimeImplicits
          with JsonImplicits
          with NetImplicits
          with LTreeImplicits
          with RangeImplicits
          with HStoreImplicits
          with SearchImplicits
          with JodaDateTimePlainImplicits
          with SearchAssistants {
        implicit val strListTypeMapper =
          new SimpleArrayJdbcType[String]("text").to(_.toList)
        implicit val playJsonArrayTypeMapper =
          new AdvancedArrayJdbcType[JsValue](
            pgjson,
            (s) =>
              utils.SimpleArrayUtils.fromString[JsValue](Json.parse(_))(s).orNull,
            (v) => utils.SimpleArrayUtils.mkString[JsValue](_.toString())(v)
          ).to(_.toList)
      }
    }
    
    object MyPostgresProfile extends MyPostgresProfile
    
  • Generated Code:

    OrderCommentsTable.scala

    package com.ben1
    // AUTO-GENERATED Slick data model for table OrderComments
    trait OrderCommentsTable {
    
      self:Tables  =>
    
      import profile.api._
      import slick.model.ForeignKeyAction
      // NOTE: GetResult mappers for plain SQL are only generated for tables where Slick knows how to map the types of all columns.
      import slick.jdbc.{GetResult => GR}
      /** Entity class storing rows of table OrderComments
       *  @param id Database column id SqlType(uuid), PrimaryKey
       *  @param vasNo Database column vas_no SqlType(varchar), Length(16,true)
       *  @param commentTs Database column comment_ts SqlType(timestamp)
       *  @param comment Database column comment SqlType(varchar), Length(1024,true), Default(None)
       *  @param fileIds Database column file_ids SqlType(_uuid), Default(None)
       *  @param photoIds Database column photo_ids SqlType(_uuid), Default(None)
       *  @param statusId Database column status_id SqlType(varchar), Length(32,true)
       *  @param commentPerson Database column comment_person SqlType(varchar), Length(64,true)
       *  @param commentPersonId Database column comment_person_id SqlType(uuid) */
      case class OrderCommentsRow(id: java.util.UUID, vasNo: String, commentTs: org.joda.time.LocalDateTime, comment: Option[String] = None, fileIds: Option[scala.collection.Seq] = None, photoIds: Option[scala.collection.Seq] = None, statusId: String, commentPerson: String, commentPersonId: java.util.UUID)
      /** GetResult implicit for fetching OrderCommentsRow objects using plain SQL queries */
      implicit def GetResultOrderCommentsRow(implicit e0: GR[java.util.UUID], e1: GR[String], e2: GR[org.joda.time.LocalDateTime], e3: GR[Option[String]], e4: GR[Option[scala.collection.Seq]]): GR[OrderCommentsRow] = GR{
        prs => import prs._
        OrderCommentsRow.tupled((<<[java.util.UUID], <<[String], <<[org.joda.time.LocalDateTime], <<?[String], <<?[scala.collection.Seq], <<?[scala.collection.Seq], <<[String], <<[String], <<[java.util.UUID]))
      }
      /** Table description of table order_comments. Objects of this class serve as prototypes for rows in queries. */
      class OrderComments(_tableTag: Tag) extends profile.api.Table[OrderCommentsRow](_tableTag, "order_comments") {
        def * = (id, vasNo, commentTs, comment, fileIds, photoIds, statusId, commentPerson, commentPersonId) <> (OrderCommentsRow.tupled, OrderCommentsRow.unapply)
        /** Maps whole row to an option. Useful for outer joins. */
        def ? = ((Rep.Some(id), Rep.Some(vasNo), Rep.Some(commentTs), comment, fileIds, photoIds, Rep.Some(statusId), Rep.Some(commentPerson), Rep.Some(commentPersonId))).shaped.<>({r=>import r._; _1.map(_=> OrderCommentsRow.tupled((_1.get, _2.get, _3.get, _4, _5, _6, _7.get, _8.get, _9.get)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))
    
        /** Database column id SqlType(uuid), PrimaryKey */
        val id: Rep[java.util.UUID] = column[java.util.UUID]("id", O.PrimaryKey)
        /** Database column vas_no SqlType(varchar), Length(16,true) */
        val vasNo: Rep[String] = column[String]("vas_no", O.Length(16,varying=true))
        /** Database column comment_ts SqlType(timestamp) */
        val commentTs: Rep[org.joda.time.LocalDateTime] = column[org.joda.time.LocalDateTime]("comment_ts")
        /** Database column comment SqlType(varchar), Length(1024,true), Default(None) */
        val comment: Rep[Option[String]] = column[Option[String]]("comment", O.Length(1024,varying=true), O.Default(None))
        /** Database column file_ids SqlType(_uuid), Default(None) */
        val fileIds: Rep[Option[scala.collection.Seq]] = column[Option[scala.collection.Seq]]("file_ids", O.Default(None))
        /** Database column photo_ids SqlType(_uuid), Default(None) */
        val photoIds: Rep[Option[scala.collection.Seq]] = column[Option[scala.collection.Seq]]("photo_ids", O.Default(None))
        /** Database column status_id SqlType(varchar), Length(32,true) */
        val statusId: Rep[String] = column[String]("status_id", O.Length(32,varying=true))
        /** Database column comment_person SqlType(varchar), Length(64,true) */
        val commentPerson: Rep[String] = column[String]("comment_person", O.Length(64,varying=true))
        /** Database column comment_person_id SqlType(uuid) */
        val commentPersonId: Rep[java.util.UUID] = column[java.util.UUID]("comment_person_id")
      /** Collection-like TableQuery object for table OrderComments */
      lazy val OrderComments = new TableQuery(tag => new OrderComments(tag))
    }
  • Sbt version information

    buld.sbt

    libraryDependencies ++= List(
      // joda time support
      "com.github.tototoshi" %% "slick-joda-mapper" % "2.4.2",
      "joda-time" % "joda-time" % "2.7",
      "org.joda" % "joda-convert" % "1.7",
      // pg extension
      "com.github.tminglei" %% "slick-pg" % "0.20.2",
      "com.github.tminglei" %% "slick-pg_joda-time" % "0.20.2",
      "com.github.tminglei" %% "slick-pg_play-json" % "0.20.2",
      "org.slf4j" % "slf4j-nop" % "1.7.26",
      "com.h2database" % "h2" % "1.4.200",
      "org.scalatest" %% "scalatest" % "3.2.6" % Test,
      "com.typesafe.slick" %% "slick" % "3.3.3",
      "org.slf4j" % "slf4j-nop" % "1.6.4",
      "com.typesafe.slick" %% "slick-hikaricp" % "3.3.3",
      "com.typesafe.slick" %% "slick-codegen" % "3.3.3",
      // pg driver
      "org.postgresql" % "postgresql" % "42.3.3"
    )
    
    scalacOptions += "-deprecation"
    run / fork := true
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant