packages feed

polysemy-hasql-0.0.1.0: integration/Polysemy/Hasql/Test/TransformMigrationTest.hs

{-# options_ghc -Wno-partial-type-signatures #-}

module Polysemy.Hasql.Test.TransformMigrationTest where

import Polysemy.Db.Data.DbError (DbError)
import qualified Polysemy.Db.Effect.Store as Store
import Polysemy.Db.Effect.Store (Store)
import Polysemy.Test (UnitTest, assertEq)
import Sqel.Column (pk)
import Sqel.Data.Dd (Sqel, (:>) ((:>)))
import Sqel.Data.Migration (Mig (Mig), Migrations, migrate)
import Sqel.Data.TableSchema (TableSchema)
import Sqel.Data.Uid (Uid (Uid))
import Sqel.Migration.Transform (MigrateTransform, migrateTransform)
import Sqel.Names (typeAs)
import Sqel.PgType (tableSchema)
import Sqel.Prim (enum, prim, primAs, prims)
import Sqel.Product (prod)
import Sqel.Query (checkQuery)
import Sqel.Uid (uid)
import Zeugma (resumeTest)

import qualified Polysemy.Hasql.Effect.Database as Database
import Polysemy.Hasql.Interpreter.DbTable (interpretTableMigrations, interpretTables)
import Polysemy.Hasql.Interpreter.Store (interpretStoreDb)
import Polysemy.Hasql.Migration (MigrateSem)
import Polysemy.Hasql.Test.RunIntegration (integrationTest)

data DatOld =
  DatOld {
    number :: Int,
    user :: Text,
    admin :: Bool
  }
  deriving stock (Eq, Show, Generic)

data Admin =
  Admin
  |
  NotAdmin
  deriving stock (Eq, Show, Generic)

adminBool :: Bool -> Admin
adminBool = \case
  True -> Admin
  False -> NotAdmin

data Meta =
  Meta {
    admin :: Admin,
    loggedIn :: Bool
  }
  deriving stock (Eq, Show, Generic)

data User =
  User {
    name :: Text,
    meta :: Meta
  }
  deriving stock (Eq, Show, Generic)

ddDatOld :: Sqel (Uid Int64 DatOld) _
ddDatOld =
  uid (pk prim) (typeAs @"User" (prod prims))

schemaOld :: TableSchema (Uid Int64 DatOld)
schemaOld =
  tableSchema ddDatOld

ddUser :: Sqel (Uid Int64 User) _
ddUser =
  uid (pk prim) (prod (prim :> prod (enum :> prim)))

schemaCur :: TableSchema (Uid Int64 User)
schemaCur =
  tableSchema ddUser

toUser :: DatOld -> User
toUser DatOld {..} =
  User {
    name = user,
    meta = Meta {admin = adminBool admin, loggedIn = False}
  }

migrations ::
  Migrations (MigrateSem r) ('[ 'Mig (Uid Int64 DatOld) (Uid Int64 User) (MigrateSem r) (MigrateTransform (MigrateSem r) (Uid Int64 DatOld) (Uid Int64 User))])
migrations =
  migrate (
    migrateTransform ddDatOld ddUser (pure . fmap (fmap toUser))
  )

target :: [Uid Int64 User]
target =
  [Uid 1 (User "user1" (Meta NotAdmin False)), Uid 2 (User "user2" (Meta Admin False))]

test_transformMigration :: UnitTest
test_transformMigration =
  integrationTest do
    interpretTables schemaOld $ interpretStoreDb schemaOld (checkQuery (primAs @"id") ddDatOld) $ resumeTest @DbError do
      Store.insert (Uid 1 (DatOld 1 "user1" False))
      Store.insert (Uid 2 (DatOld 2 "user2" True))
    resumeTest @DbError Database.release
    resumeTest @DbError Database.resetInit
    interpretTableMigrations schemaCur migrations $
      interpretStoreDb schemaCur (checkQuery (primAs @"id") ddUser) $
      restop @DbError @(Store _ _) do
        assertEq target =<< Store.fetchAll