nafg / slick-migration-api

Schema manipulation dialects and DSL for Slick

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Allow adding non-optional columns

andreas-pabst opened this issue · comments

I ran into an issue when adding non-null (not optional) columns when the table has data stored in it.

To my understanding a migration is not possible because the rows in the table would not fit the "not null" constraint.

In an concrete example I have a user table and case class:

case class User(uid : String, name : String)

class UserTable(tag : Tag) extends Table[User](tag, "users"){
    def uid = column[String]("uid", O.PrimaryKey, O.Length(255))
    def name = column[String]("name", O.Length(255))

    override def * = (uid, name) <> (User.tupled, User.unapply)
 }

 lazy val users = TableQuery[UserTable]

The table is then populated with one user:

db.run(users += User("uid", "name"))

After the insertion of the first user I want to add a column created (with the correct ColumnConversion for JodaTime in place). The User and UserTable now look like this:

case class User(uid : String, name : String, created : DateTime)

class UserTable(tag : Tag) extends Table[User](tag, "users"){
    def uid = column[String]("uid", O.PrimaryKey, O.Length(255))
    def name = column[String]("name", O.Length(255))
    def created = column[DateTime]("created")

    override def * = (uid, name) <> (User.tupled, User.unapply)
 }

 lazy val users = TableQuery[UserTable]

The migration looks like this:

implicit val dialect = GenericDialect.apply(H2Profile) 

val migration = TableMigration(users).addColumns(_.created)
db.run(migration())

Logging the migration statement produces the following output:

List(alter table "users" add column "created" TIMESTAMP NOT NULL)

which is the desired result, however due to the table already having data in it, it is not possible to add a column without allowing null values.
Is there any way to add a non nullable column to a table with existing data?
Are you aware of one work-around?

One work-around I thought of is:
I thought that maybe I have to copy all the existing data to a new temporary table, then remove all the data from the original table, add the column to the original table, add the data from the temporary table with a supplier function for the new column and finally drop the temporary table.

Please tell me if you are aware of an elegant solution to my stated problem.

Thanks for the fast replay.
I would prefer the second approach.

Can you point me into the right direction so that I don't have to

  1. Create a class with the optional column migrate to that class
  2. Add the data
  3. Have the final desired class with the non-optional column which I can use for the final migration back to the non-nullable column?

👍 For pointing out the obvious :)