valderman / selda

A type-safe, high-level SQL library for Haskell
https://selda.link
MIT License
478 stars 58 forks source link

Migrations failing validation on tables with primary keys #133

Closed expede closed 4 years ago

expede commented 4 years ago

Hi there — big fan of this project, and have really been enjoying using it so far. Unfortunately, I'm having some issues with migrations on 0.5.0.0 where migrate (and autoMigrate) fail, even on newly created tables.

I did some simple troubleshooting, and came up with some results that point in the direction of validation.

data User = User
  { userID        :: ID User
  , role          :: Role
  , active        :: Bool
  , secretDigest  :: SecretDigest
  , insertedAt    :: UTCTime
  , modifiedAt    :: UTCTime
  } deriving ( Show
             , Eq
             , Generic
             , SqlRow
             )

userTable = table "users"
  [ #userID :- autoPrimary
  , #active :- index
  ]
λ> runApp $ tryDropTable userTable
()

λ> runApp $ createTable userTable
()

λ> runApp $ validateTable users
*** Exception: ValidationError "error validating table \"users\":\ntable shouldn't have a primary key constraint group, but does in database:\n(\"userID\")"

λ> runApp $ diffTable users
table shouldn't have a primary key constraint group, but does in database:
("userID")

...which is strange, because it is listed as being a primary key in the Selda table definition. Any thoughts?


In either case, I'm trying to add a new columns... but am not sure if this approach is correct because I haven't been able to get any version of this to work. Perhaps the issue is somewhere in here? (Renamed the above User to User0, and created a new data User that has the required column)

  [ Migration user0Table Table.users \oldUser -> pure $ new
      [ #userID        := cast (oldUser ! #userID)
      , #username      := toString (oldUser ! #userID)
      , #role          := oldUser ! #role
      , #active        := oldUser ! #active
      , #secretDigest  := oldUser ! #secretDigest
      , #insertedAt    := oldUser ! #insertedAt
      , #modifiedAt    := oldUser ! #modifiedAt
      ]
  ]
valderman commented 4 years ago

Hm, I suspect that we messed something up here when we introduced composite primary keys. Prior to that, PKs were checked in a completely different way for the purpose of migrations.

Have you experienced this on both PostgreSQL and SQLite backends, or only one of them?

expede commented 4 years ago

It's happening on PostgreSQL — I haven't tried on SQLite.

valderman commented 4 years ago

Thanks for bringing this to my attention, this turned out to be related to three different bugs. Those bugs managed to cancel each other out in various circumstances, which is how it made it past testing. All three should be fixed by now, but please let me know if you still see this issue with latest HEAD.