{-# LANGUAGE QuasiQuotes #-}

-- | Postgres DDL Source Version
--
-- Deals with catalog version - used by 'Hasura.Backends.Postgres.DDL.Source'.
module Hasura.Backends.Postgres.DDL.Source.Version
  ( SourceCatalogVersion,
    initialSourceCatalogVersion,
    latestSourceCatalogVersion,
    previousSourceCatalogVersions,
    getSourceCatalogVersion,
    setSourceCatalogVersion,
  )
where

import Data.Text qualified as T
import Database.PG.Query qualified as PG
import Hasura.Backends.Postgres.Connection
import Hasura.Base.Error
import Hasura.Prelude
import Hasura.RQL.Types.BackendType (BackendType (Postgres), PostgresKind)
import Hasura.Server.Migrate.Version qualified as Version

type SourceCatalogVersion (pgKind :: PostgresKind) = Version.SourceCatalogVersion ('Postgres pgKind)

initialSourceCatalogVersion :: SourceCatalogVersion pgKind
initialSourceCatalogVersion :: forall (pgKind :: PostgresKind). SourceCatalogVersion pgKind
initialSourceCatalogVersion = Int -> SourceCatalogVersion ('Postgres pgKind)
forall (backend :: BackendType).
Int -> SourceCatalogVersion backend
Version.SourceCatalogVersion Int
0

latestSourceCatalogVersion :: SourceCatalogVersion pgKind
latestSourceCatalogVersion :: forall (pgKind :: PostgresKind). SourceCatalogVersion pgKind
latestSourceCatalogVersion = Int -> SourceCatalogVersion ('Postgres pgKind)
forall (backend :: BackendType).
Int -> SourceCatalogVersion backend
Version.SourceCatalogVersion Int
3

previousSourceCatalogVersions :: [SourceCatalogVersion pgKind]
previousSourceCatalogVersions :: forall (pgKind :: PostgresKind). [SourceCatalogVersion pgKind]
previousSourceCatalogVersions = [SourceCatalogVersion pgKind
forall (pgKind :: PostgresKind). SourceCatalogVersion pgKind
initialSourceCatalogVersion .. SourceCatalogVersion pgKind -> SourceCatalogVersion pgKind
forall a. Enum a => a -> a
pred SourceCatalogVersion pgKind
forall (pgKind :: PostgresKind). SourceCatalogVersion pgKind
latestSourceCatalogVersion]

setSourceCatalogVersion :: (MonadTx m) => m ()
setSourceCatalogVersion :: forall (m :: * -> *). MonadTx m => m ()
setSourceCatalogVersion =
  TxE QErr () -> m ()
forall a. TxE QErr a -> m a
forall (m :: * -> *) a. MonadTx m => TxE QErr a -> m a
liftTx
    (TxE QErr () -> m ()) -> TxE QErr () -> m ()
forall a b. (a -> b) -> a -> b
$ (PGTxErr -> QErr) -> Query -> Identity Text -> Bool -> TxE QErr ()
forall (m :: * -> *) r e.
(MonadIO m, ToPrepArgs r) =>
(PGTxErr -> e) -> Query -> r -> Bool -> TxET e m ()
PG.unitQE
      PGTxErr -> QErr
defaultTxErrorHandler
      [PG.sql|
        INSERT INTO hdb_catalog.hdb_source_catalog_version(version, upgraded_on)
          VALUES ($1, NOW())
        ON CONFLICT ((version IS NOT NULL))
        DO UPDATE SET version = $1, upgraded_on = NOW()
      |]
      (Text -> Identity Text
forall a. a -> Identity a
Identity (SourceCatalogVersion Any -> Text
forall a. Show a => a -> Text
tshow SourceCatalogVersion Any
forall (pgKind :: PostgresKind). SourceCatalogVersion pgKind
latestSourceCatalogVersion))
      Bool
False

getSourceCatalogVersion :: (MonadTx m) => m (SourceCatalogVersion postgres)
getSourceCatalogVersion :: forall (m :: * -> *) (postgres :: PostgresKind).
MonadTx m =>
m (SourceCatalogVersion postgres)
getSourceCatalogVersion = do
  Text
versionText <-
    TxE QErr Text -> m Text
forall a. TxE QErr a -> m a
forall (m :: * -> *) a. MonadTx m => TxE QErr a -> m a
liftTx
      (TxE QErr Text -> m Text) -> TxE QErr Text -> m Text
forall a b. (a -> b) -> a -> b
$ Identity Text -> Text
forall a. Identity a -> a
runIdentity
      (Identity Text -> Text)
-> (SingleRow (Identity Text) -> Identity Text)
-> SingleRow (Identity Text)
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SingleRow (Identity Text) -> Identity Text
forall a. SingleRow a -> a
PG.getRow
      (SingleRow (Identity Text) -> Text)
-> TxET QErr IO (SingleRow (Identity Text)) -> TxE QErr Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (PGTxErr -> QErr)
-> Query -> () -> Bool -> TxET QErr IO (SingleRow (Identity Text))
forall (m :: * -> *) a r e.
(MonadIO m, FromRes a, ToPrepArgs r) =>
(PGTxErr -> e) -> Query -> r -> Bool -> TxET e m a
PG.withQE
        PGTxErr -> QErr
defaultTxErrorHandler
        [PG.sql| SELECT version FROM hdb_catalog.hdb_source_catalog_version |]
        ()
        Bool
False
  String -> Either String (SourceCatalogVersion postgres)
forall a. Read a => String -> Either String a
readEither (Text -> String
T.unpack Text
versionText) Either String (SourceCatalogVersion postgres)
-> (String -> m (SourceCatalogVersion postgres))
-> m (SourceCatalogVersion postgres)
forall (m :: * -> *) e a.
Applicative m =>
Either e a -> (e -> m a) -> m a
`onLeft` (Text -> m (SourceCatalogVersion postgres)
forall (m :: * -> *) a. QErrM m => Text -> m a
throw500 (Text -> m (SourceCatalogVersion postgres))
-> (String -> Text) -> String -> m (SourceCatalogVersion postgres)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Text
"Invalid source catalog version in the metadata: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) (Text -> Text) -> (String -> Text) -> String -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack))