2022-04-29 05:13:13 +03:00
|
|
|
{-# LANGUAGE DeriveAnyClass #-}
|
|
|
|
{-# LANGUAGE QuasiQuotes #-}
|
|
|
|
|
2021-03-15 16:02:58 +03:00
|
|
|
module Hasura.SQL.Backend
|
2021-09-24 01:56:37 +03:00
|
|
|
( PostgresKind (..),
|
|
|
|
BackendType (..),
|
2022-04-29 05:13:13 +03:00
|
|
|
BackendSourceKind (..),
|
2021-09-24 01:56:37 +03:00
|
|
|
backendShortName,
|
|
|
|
supportedBackends,
|
2022-04-29 05:13:13 +03:00
|
|
|
backendTextNames,
|
|
|
|
backendTypeFromText,
|
|
|
|
parseBackendTypeFromText,
|
|
|
|
backendTypeFromBackendSourceKind,
|
2021-09-24 01:56:37 +03:00
|
|
|
)
|
|
|
|
where
|
2021-04-22 00:44:37 +03:00
|
|
|
|
2021-09-24 01:56:37 +03:00
|
|
|
import Data.Aeson
|
2022-04-29 05:13:13 +03:00
|
|
|
import Data.Aeson.Types (Parser)
|
2021-09-24 01:56:37 +03:00
|
|
|
import Data.Proxy
|
|
|
|
import Data.Text (unpack)
|
|
|
|
import Data.Text.Extended
|
2022-04-29 05:13:13 +03:00
|
|
|
import Data.Text.NonEmpty (NonEmptyText, mkNonEmptyText, nonEmptyTextQQ)
|
2022-05-02 08:03:12 +03:00
|
|
|
import Hasura.Backends.DataConnector.Adapter.Types (DataConnectorName (..))
|
2021-09-24 01:56:37 +03:00
|
|
|
import Hasura.Incremental
|
|
|
|
import Hasura.Prelude
|
2022-04-29 05:13:13 +03:00
|
|
|
import Witch qualified
|
2021-04-22 00:44:37 +03:00
|
|
|
|
|
|
|
-- | Argument to Postgres; we represent backends which are variations on Postgres as sub-types of
|
|
|
|
-- Postgres. This value indicates which "flavour" of Postgres a backend is.
|
|
|
|
data PostgresKind
|
|
|
|
= Vanilla
|
2021-05-21 05:46:58 +03:00
|
|
|
| Citus
|
2022-04-29 05:13:13 +03:00
|
|
|
deriving stock (Show, Eq, Ord, Generic)
|
|
|
|
deriving anyclass (Hashable, Cacheable)
|
2021-02-14 09:07:52 +03:00
|
|
|
|
|
|
|
-- | An enum that represents each backend we support.
|
2021-03-18 23:34:11 +03:00
|
|
|
data BackendType
|
2021-04-22 00:44:37 +03:00
|
|
|
= Postgres PostgresKind
|
2021-03-18 23:34:11 +03:00
|
|
|
| MSSQL
|
2021-04-12 13:18:29 +03:00
|
|
|
| BigQuery
|
2021-07-15 15:44:26 +03:00
|
|
|
| MySQL
|
2022-05-02 08:03:12 +03:00
|
|
|
| DataConnector
|
2022-04-29 05:13:13 +03:00
|
|
|
deriving stock (Show, Eq, Ord, Generic)
|
|
|
|
deriving anyclass (Hashable, Cacheable)
|
2021-04-22 00:44:37 +03:00
|
|
|
|
2021-03-18 23:34:11 +03:00
|
|
|
-- | The name of the backend, as we expect it to appear in our metadata and API.
|
2022-04-29 05:13:13 +03:00
|
|
|
instance Witch.From BackendType NonEmptyText where
|
|
|
|
from (Postgres Vanilla) = [nonEmptyTextQQ|postgres|]
|
|
|
|
from (Postgres Citus) = [nonEmptyTextQQ|citus|]
|
|
|
|
from MSSQL = [nonEmptyTextQQ|mssql|]
|
|
|
|
from BigQuery = [nonEmptyTextQQ|bigquery|]
|
|
|
|
from MySQL = [nonEmptyTextQQ|mysql|]
|
2022-05-02 08:03:12 +03:00
|
|
|
from DataConnector = [nonEmptyTextQQ|dataconnector|]
|
2022-04-29 05:13:13 +03:00
|
|
|
|
2021-03-18 23:34:11 +03:00
|
|
|
instance ToTxt BackendType where
|
2022-04-29 05:13:13 +03:00
|
|
|
toTxt = toTxt . Witch.into @NonEmptyText
|
|
|
|
|
2021-03-18 23:34:11 +03:00
|
|
|
instance FromJSON BackendType where
|
2022-04-29 05:13:13 +03:00
|
|
|
parseJSON = withText "backend type" parseBackendTypeFromText
|
2021-03-18 23:34:11 +03:00
|
|
|
|
|
|
|
instance ToJSON BackendType where
|
|
|
|
toJSON = String . toTxt
|
|
|
|
|
2021-04-22 00:44:37 +03:00
|
|
|
instance Cacheable (Proxy (b :: BackendType))
|
|
|
|
|
2022-05-02 08:03:12 +03:00
|
|
|
-- | Similar to 'BackendType', however, in the case of 'DataConnectorKind' we need to be able
|
|
|
|
-- capture the name of the data connector that should be used by the DataConnector backend.
|
2022-04-29 05:13:13 +03:00
|
|
|
-- This type correlates to the kind property of 'SourceMetadata', which is usually just
|
2022-05-02 08:03:12 +03:00
|
|
|
-- postgres, mssql, etc for static backends, but can be a configurable value for DataConnector
|
|
|
|
-- hence requiring 'DataConnectorName' for 'DataConnectorKind'
|
2022-04-29 05:13:13 +03:00
|
|
|
--
|
|
|
|
-- This type cannot entirely replace 'BackendType' because 'BackendType' has a fixed number of
|
|
|
|
-- possible values which can be enumerated over at compile time, but 'BackendSourceKind' does
|
2022-05-02 08:03:12 +03:00
|
|
|
-- not because DataConnector fundamentally is configured at runtime with 'DataConnectorName'.
|
2022-04-29 05:13:13 +03:00
|
|
|
data BackendSourceKind (b :: BackendType) where
|
|
|
|
PostgresVanillaKind :: BackendSourceKind ('Postgres 'Vanilla)
|
|
|
|
PostgresCitusKind :: BackendSourceKind ('Postgres 'Citus)
|
|
|
|
MSSQLKind :: BackendSourceKind 'MSSQL
|
|
|
|
BigQueryKind :: BackendSourceKind 'BigQuery
|
|
|
|
MySQLKind :: BackendSourceKind 'MySQL
|
2022-05-02 08:03:12 +03:00
|
|
|
DataConnectorKind :: DataConnectorName -> BackendSourceKind 'DataConnector
|
2022-04-29 05:13:13 +03:00
|
|
|
|
|
|
|
deriving instance Show (BackendSourceKind b)
|
|
|
|
|
|
|
|
deriving instance Eq (BackendSourceKind b)
|
|
|
|
|
|
|
|
deriving instance Ord (BackendSourceKind b)
|
|
|
|
|
|
|
|
instance Cacheable (BackendSourceKind b) where
|
|
|
|
unchanged _ = (==)
|
|
|
|
|
|
|
|
instance Witch.From (BackendSourceKind b) NonEmptyText where
|
|
|
|
-- All cases are specified explicitly here to ensure compiler warnings highlight
|
|
|
|
-- this area for consideration and update if another BackendType is added
|
|
|
|
from k@PostgresVanillaKind = Witch.into @NonEmptyText $ backendTypeFromBackendSourceKind k
|
|
|
|
from k@PostgresCitusKind = Witch.into @NonEmptyText $ backendTypeFromBackendSourceKind k
|
|
|
|
from k@MSSQLKind = Witch.into @NonEmptyText $ backendTypeFromBackendSourceKind k
|
|
|
|
from k@BigQueryKind = Witch.into @NonEmptyText $ backendTypeFromBackendSourceKind k
|
|
|
|
from k@MySQLKind = Witch.into @NonEmptyText $ backendTypeFromBackendSourceKind k
|
2022-05-02 08:03:12 +03:00
|
|
|
from (DataConnectorKind dataConnectorName) = Witch.into @NonEmptyText dataConnectorName
|
2022-04-29 05:13:13 +03:00
|
|
|
|
|
|
|
instance ToTxt (BackendSourceKind b) where
|
|
|
|
toTxt = toTxt . Witch.into @NonEmptyText
|
|
|
|
|
|
|
|
-- If you need to parse an arbitrary string into a BackendSourceKind, you can't because of the
|
|
|
|
-- b type parameter. You actually want to parse into 'AnyBackend BackendSourceKind'.
|
|
|
|
-- See 'backendSourceKindFromText' from the AnyBackend module for that.
|
|
|
|
|
|
|
|
instance ToJSON (BackendSourceKind b) where
|
|
|
|
toJSON = String . toTxt
|
|
|
|
|
|
|
|
instance FromJSON (BackendSourceKind ('Postgres 'Vanilla)) where
|
|
|
|
parseJSON = mkParseStaticBackendSourceKind PostgresVanillaKind
|
|
|
|
|
|
|
|
instance FromJSON (BackendSourceKind ('Postgres 'Citus)) where
|
|
|
|
parseJSON = mkParseStaticBackendSourceKind PostgresCitusKind
|
|
|
|
|
|
|
|
instance FromJSON (BackendSourceKind ('MSSQL)) where
|
|
|
|
parseJSON = mkParseStaticBackendSourceKind MSSQLKind
|
|
|
|
|
|
|
|
instance FromJSON (BackendSourceKind ('BigQuery)) where
|
|
|
|
parseJSON = mkParseStaticBackendSourceKind BigQueryKind
|
|
|
|
|
|
|
|
instance FromJSON (BackendSourceKind ('MySQL)) where
|
|
|
|
parseJSON = mkParseStaticBackendSourceKind MySQLKind
|
|
|
|
|
2022-05-02 08:03:12 +03:00
|
|
|
instance FromJSON (BackendSourceKind ('DataConnector)) where
|
2022-04-29 05:13:13 +03:00
|
|
|
parseJSON = withText "BackendSourceKind" $ \text ->
|
2022-05-02 08:03:12 +03:00
|
|
|
DataConnectorKind . DataConnectorName <$> mkNonEmptyText text
|
2022-04-29 05:13:13 +03:00
|
|
|
`onNothing` fail "Cannot be empty string"
|
|
|
|
|
|
|
|
mkParseStaticBackendSourceKind :: BackendSourceKind b -> (Value -> Parser (BackendSourceKind b))
|
|
|
|
mkParseStaticBackendSourceKind backendSourceKind =
|
|
|
|
withText "BackendSourceKind" $ \text ->
|
|
|
|
if text `elem` validValues
|
|
|
|
then pure backendSourceKind
|
|
|
|
else fail ("got: " <> unpack text <> ", expected one of: " <> unpack (commaSeparated validValues))
|
|
|
|
where
|
|
|
|
validValues = backendTextNames $ backendTypeFromBackendSourceKind backendSourceKind
|
|
|
|
|
2021-07-07 04:43:42 +03:00
|
|
|
-- | Some generated APIs use a shortened version of the backend's name rather than its full
|
|
|
|
-- name. This function returns the "short form" of a backend, if any.
|
2022-04-29 05:13:13 +03:00
|
|
|
backendShortName :: BackendType -> Maybe Text
|
2021-07-07 04:43:42 +03:00
|
|
|
backendShortName = \case
|
2022-04-29 05:13:13 +03:00
|
|
|
Postgres Vanilla -> Just "pg"
|
|
|
|
_ -> Nothing
|
2021-07-07 04:43:42 +03:00
|
|
|
|
2021-03-18 23:34:11 +03:00
|
|
|
supportedBackends :: [BackendType]
|
2021-04-22 00:44:37 +03:00
|
|
|
supportedBackends =
|
2021-09-24 01:56:37 +03:00
|
|
|
[ Postgres Vanilla,
|
|
|
|
Postgres Citus,
|
|
|
|
MSSQL,
|
|
|
|
BigQuery,
|
2021-12-22 03:10:28 +03:00
|
|
|
MySQL,
|
2022-05-02 08:03:12 +03:00
|
|
|
DataConnector
|
2021-04-22 00:44:37 +03:00
|
|
|
]
|
2022-04-29 05:13:13 +03:00
|
|
|
|
|
|
|
backendTextNames :: BackendType -> [Text]
|
|
|
|
backendTextNames b =
|
|
|
|
catMaybes
|
|
|
|
[ Just (toTxt b), -- long form
|
|
|
|
backendShortName b -- short form
|
|
|
|
]
|
|
|
|
|
|
|
|
backendTextNameLookup :: [(Text, BackendType)]
|
|
|
|
backendTextNameLookup =
|
|
|
|
supportedBackends >>= (\b -> (,b) <$> backendTextNames b)
|
|
|
|
|
|
|
|
-- | This uses this lookup mechanism to avoid having to duplicate and hardcode the
|
|
|
|
-- backend string. We accept both the short form and the long form of the backend's name.
|
|
|
|
backendTypeFromText :: Text -> Maybe BackendType
|
|
|
|
backendTypeFromText txt =
|
|
|
|
lookup txt backendTextNameLookup
|
|
|
|
|
|
|
|
parseBackendTypeFromText :: Text -> Parser BackendType
|
|
|
|
parseBackendTypeFromText txt =
|
|
|
|
let uniqueBackends = commaSeparated $ fst <$> backendTextNameLookup
|
|
|
|
in backendTypeFromText txt
|
|
|
|
`onNothing` fail ("got: " <> unpack txt <> ", expected one of: " <> unpack uniqueBackends)
|
|
|
|
|
|
|
|
backendTypeFromBackendSourceKind :: BackendSourceKind b -> BackendType
|
|
|
|
backendTypeFromBackendSourceKind = \case
|
|
|
|
PostgresVanillaKind -> Postgres Vanilla
|
|
|
|
PostgresCitusKind -> Postgres Citus
|
|
|
|
MSSQLKind -> MSSQL
|
|
|
|
BigQueryKind -> BigQuery
|
|
|
|
MySQLKind -> MySQL
|
2022-05-02 08:03:12 +03:00
|
|
|
DataConnectorKind _ -> DataConnector
|