@@ -60,6 +60,14 @@ AdminUser sql=admin_users
6060
6161 promotedByUserId UserId
6262 UniquePromotedByUserId promotedByUserId
63+
64+ FKParent sql=migration_fk_parent
65+
66+ FKChildV1 sql=migration_fk_child
67+
68+ -- Simulate creating a new FK field on an existing table
69+ FKChildV2 sql=migration_fk_child
70+ parentId FKParentId
6371|]
6472
6573userEntityDef :: EntityDef
@@ -77,15 +85,28 @@ password2EntityDef = entityDef (Proxy :: Proxy Password2)
7785adminUserEntityDef :: EntityDef
7886adminUserEntityDef = entityDef (Proxy :: Proxy AdminUser )
7987
88+ fkParentEntityDef :: EntityDef
89+ fkParentEntityDef = entityDef (Proxy :: Proxy FKParent )
90+
91+ fkChildV1EntityDef :: EntityDef
92+ fkChildV1EntityDef = entityDef (Proxy :: Proxy FKChildV1 )
93+
94+ fkChildV2EntityDef :: EntityDef
95+ fkChildV2EntityDef = entityDef (Proxy :: Proxy FKChildV2 )
96+
97+ -- Note that FKChild is deliberately omitted here because we have two
98+ -- versions of it
8099allEntityDefs :: [EntityDef ]
81100allEntityDefs =
82101 [ userEntityDef
83102 , userFriendshipEntityDef
84103 , passwordEntityDef
85104 , password2EntityDef
86105 , adminUserEntityDef
106+ , fkParentEntityDef
87107 ]
88108
109+ -- Note that this function migrates to the schema expected by FKChildV1
89110migrateManually :: (HasCallStack , MonadIO m ) => SqlPersistT m ()
90111migrateManually = do
91112 cleanDB
@@ -150,6 +171,8 @@ migrateManually = do
150171 , " ADD CONSTRAINT unique_promoted_by_user_id"
151172 , " UNIQUE(promoted_by_user_id);"
152173 ]
174+ rawEx " CREATE TABLE migration_fk_parent(id int8 primary key);"
175+ rawEx " CREATE TABLE migration_fk_child(id int8 primary key);"
153176 rawEx " CREATE TABLE ignored(id int8 primary key);"
154177
155178cleanDB :: (HasCallStack , MonadIO m ) => SqlPersistT m ()
@@ -162,6 +185,8 @@ cleanDB = do
162185 rawEx " DROP TABLE IF EXISTS ignored;"
163186 rawEx " DROP TABLE IF EXISTS admin_users;"
164187 rawEx " DROP TABLE IF EXISTS users;"
188+ rawEx " DROP TABLE IF EXISTS migration_fk_child;"
189+ rawEx " DROP TABLE IF EXISTS migration_fk_parent;"
165190
166191spec :: Spec
167192spec = describe " MigrationSpec" $ do
@@ -582,3 +607,27 @@ spec = describe "MigrationSpec" $ do
582607 result2 <-
583608 liftIO $ migrateEntitiesStructured getter allEntityDefs allEntityDefs
584609 result2 `shouldBe` Right []
610+
611+ it " suggests FK constraints for new fields first time" $ runConnAssert $ do
612+ migrateManually
613+
614+ getter <- getStmtGetter
615+ result <-
616+ liftIO $
617+ migrateEntitiesStructured
618+ getter
619+ (fkChildV2EntityDef : allEntityDefs)
620+ [fkChildV2EntityDef]
621+
622+ cleanDB
623+
624+ case result of
625+ Right [] ->
626+ pure ()
627+ Left err ->
628+ expectationFailure $ show err
629+ Right alters ->
630+ map (snd . showAlterDb) alters
631+ `shouldBe` [ " ALTER TABLE \" migration_fk_child\" ADD COLUMN \" parent_id\" INT8 NOT NULL"
632+ , " ALTER TABLE \" migration_fk_child\" ADD CONSTRAINT \" migration_fk_child_parent_id_fkey\" FOREIGN KEY(\" parent_id\" ) REFERENCES \" migration_fk_parent\" (\" id\" ) ON DELETE RESTRICT ON UPDATE RESTRICT"
633+ ]
0 commit comments