Skip to content

Fixed migration generation for tuples containing records that need migration #53

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

Open
wants to merge 3 commits into
base: lamdera-next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions extra/Lamdera/Evergreen/MigrationGenerator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -579,20 +579,41 @@ canToMigration_ oldVersion newVersion scope interfaces recursionSet typeNew type
case typeOld of
Can.TTuple a2 b2 c2m ->
let
-- Helper function to detect if a migration needs lambda wrapping for tuple operations
needsLambdaWrap :: Can.Type -> Bool
needsLambdaWrap t = isRecord t

-- Generate unique variable name based on current context to avoid shadowing
tupleVarName = nextUniqueRef oldValueRef

-- Generate migrations with appropriate value references for tuple operations
nestedValueRef1 = if needsLambdaWrap a1 then tupleVarName else oldValueRef
m1@(MigrationNested mfn1 imps1 subDefs1) =
canToMigration oldVersion newVersion scope interfaces recursionSet a1 (Just a2) tvarMapOld tvarMapNew oldValueRef
canToMigration oldVersion newVersion scope interfaces recursionSet a1 (Just a2) tvarMapOld tvarMapNew nestedValueRef1

nestedValueRef2 = if needsLambdaWrap b1 then tupleVarName else oldValueRef
m2@(MigrationNested mfn2 imps2 subDefs2) =
canToMigration oldVersion newVersion scope interfaces recursionSet b1 (Just b2) tvarMapOld tvarMapNew oldValueRef
canToMigration oldVersion newVersion scope interfaces recursionSet b1 (Just b2) tvarMapOld tvarMapNew nestedValueRef2

-- Helper function to wrap migrations that need lambda wrapping
wrapIfNeeded :: Can.Type -> Text -> Text
wrapIfNeeded t migration =
if needsLambdaWrap t && T.strip migration /= "" then
T.concat ["(\\", tupleVarName, " -> ", migration, ")"]
else
migration

migrateTuple :: (Text -> Text) -> (Text -> Text) -> (Text -> Text -> Text) -> Migration
migrateTuple handle1 handle2 handleBoth =
let
wrappedMfn1 = wrapIfNeeded a1 mfn1
wrappedMfn2 = wrapIfNeeded b1 mfn2
(migration, migrationDefs) =
case (T.strip mfn1 == "", T.strip mfn2 == "") of
(True, True) -> ("", Map.empty) -- No migration necessary
(False, True) -> (handle1 mfn1, subDefs1)
(True, False) -> (handle2 mfn2, subDefs2)
(False, False) -> (handleBoth mfn1 mfn2, subDefs1 <> subDefs2)
(False, True) -> (handle1 wrappedMfn1, subDefs1)
(True, False) -> (handle2 wrappedMfn2, subDefs2)
(False, False) -> (handleBoth wrappedMfn1 wrappedMfn2, subDefs1 <> subDefs2)
in
xMigrationNested (migration, imps1 <> imps2, migrationDefs)
in
Expand Down
2 changes: 1 addition & 1 deletion test/Test/Lamdera/Evergreen/TestMigrationGenerator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ testMigrationGeneration scenario oldVersion newVersion = do

_ <- io $ Lamdera.Relative.writeFile ("test/scenario-migration-generate/src/Evergreen/Migrate/VX" <> show newVersion <> ".elm") result

expectEqualTextTrimmed result (mock & withDefault "failed to load file")
expectEqualTextTrimmed (mock & withDefault "failed to load file") result

let filenames =
[ "src/Evergreen/V" <> show oldVersion <> "/Types.elm"
Expand Down
25 changes: 25 additions & 0 deletions test/scenario-migration-generate/src/Evergreen/Migrate/V2.elm
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ migrate_Types_BackendModel old =
, time = old.time
, userCache = old.userCache |> migrate_AssocList_Dict identity migrate_IncludedBySpecialCasedParam_Custom
, apps = (Unimplemented {- Type `Dict (String) (Evergreen.V2.Types.App)` was added in V2. I need you to set a default value. -})
, user = old.user |> migrate_Types_User
, depthTests = (Unimplemented {- Field of type `Dict (String) (Evergreen.V1.Types.Depth)` was removed in V2. I need you to do something with the `old.depthTests` value if you wish to keep the data, then remove this line. -})
, removed = (Unimplemented {- Field of type `String` was removed in V2. I need you to do something with the `old.removed` value if you wish to keep the data, then remove this line. -})
, removedRecord = (Unimplemented {- Field of type `Evergreen.V1.External.AllCoreTypes` was removed in V2. I need you to do something with the `old.removedRecord` value if you wish to keep the data, then remove this line. -})
Expand Down Expand Up @@ -230,6 +231,30 @@ migrate_Types_FrontendMsg_ old =
Evergreen.V2.Types.AllCoreTypes (p0 |> migrate_External_AllCoreTypes)


migrate_Types_User : Evergreen.V1.Types.User -> Evergreen.V2.Types.User
migrate_Types_User old =
old
|> Tuple.mapSecond
(\rec ->
{ name = rec.name
, userType = rec.userType |> migrate_Types_UserType
, parents =
rec.parents
|> Tuple.mapBoth
(\rec1 ->
{ name = rec1.name
, userType = rec1.userType |> migrate_Types_UserType
}
)
(\rec1 ->
{ name = rec1.name
, userType = rec1.userType |> migrate_Types_UserType
}
)
}
)


migrate_Types_UserType : Evergreen.V1.Types.UserType -> Evergreen.V2.Types.UserType
migrate_Types_UserType old =
case old of
Expand Down
4 changes: 4 additions & 0 deletions test/scenario-migration-generate/src/Evergreen/V1/Types.elm
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ type alias BackendModel =

-- WIP
, depthTests : Dict String Depth
, user : User
}

type alias User =
( Int, { name : String, userType : UserType, parents: ( { name : String, userType : UserType }, { name : String, userType : UserType } ) } )


type UserType
= UserFirst
Expand Down
3 changes: 3 additions & 0 deletions test/scenario-migration-generate/src/Evergreen/V2/Types.elm
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@ type alias BackendModel =

-- WIP
, apps : Dict String App
, user : User
}

type alias User =
( Int, { name : String, userType : UserType, parents: ( { name : String, userType : UserType }, { name : String, userType : UserType } ) } )

type UserType
= UserFirst
Expand Down