2022-02-25 19:08:18 +03:00
|
|
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
|
|
|
|
2022-05-02 08:03:12 +03:00
|
|
|
module Hasura.Backends.DataConnector.Adapter.Metadata () where
|
2022-02-25 19:08:18 +03:00
|
|
|
|
2022-04-14 05:06:07 +03:00
|
|
|
import Data.Aeson qualified as J
|
|
|
|
import Data.Environment (Environment)
|
|
|
|
import Data.HashMap.Strict qualified as Map
|
2022-04-29 05:13:13 +03:00
|
|
|
import Data.HashMap.Strict.InsOrd qualified as OMap
|
2022-04-14 05:06:07 +03:00
|
|
|
import Data.Sequence.NonEmpty qualified as NESeq
|
|
|
|
import Data.Text.Extended (toTxt)
|
2022-05-02 08:03:12 +03:00
|
|
|
import Hasura.Backends.DataConnector.API qualified as API
|
|
|
|
import Hasura.Backends.DataConnector.Adapter.Types (ConnSourceConfig (..))
|
|
|
|
import Hasura.Backends.DataConnector.Adapter.Types qualified as DC
|
|
|
|
import Hasura.Backends.DataConnector.Agent.Client qualified as Agent.Client
|
|
|
|
import Hasura.Backends.DataConnector.IR.Expression qualified as IR.E
|
|
|
|
import Hasura.Backends.DataConnector.IR.Name qualified as IR.N
|
|
|
|
import Hasura.Backends.DataConnector.IR.Scalar.Type qualified as IR.S.T
|
|
|
|
import Hasura.Backends.DataConnector.IR.Table qualified as IR.T
|
2022-04-14 05:06:07 +03:00
|
|
|
import Hasura.Backends.Postgres.SQL.Types (PGDescription (..))
|
|
|
|
import Hasura.Base.Error (Code (..), QErr, throw400, withPathK)
|
2022-02-25 19:08:18 +03:00
|
|
|
import Hasura.Prelude
|
2022-04-14 05:06:07 +03:00
|
|
|
import Hasura.RQL.IR.BoolExp (OpExpG (..), PartialSQLExp (..))
|
2022-04-28 04:51:58 +03:00
|
|
|
import Hasura.RQL.Types.Column qualified as RQL.T.C
|
2022-04-14 05:06:07 +03:00
|
|
|
import Hasura.RQL.Types.Common (OID (..), SourceName)
|
|
|
|
import Hasura.RQL.Types.Metadata (SourceMetadata (..))
|
2022-02-25 19:08:18 +03:00
|
|
|
import Hasura.RQL.Types.Metadata.Backend (BackendMetadata (..))
|
2022-04-14 05:06:07 +03:00
|
|
|
import Hasura.RQL.Types.Source (ResolvedSource (..))
|
|
|
|
import Hasura.RQL.Types.SourceCustomization (SourceTypeCustomization)
|
2022-04-28 04:51:58 +03:00
|
|
|
import Hasura.RQL.Types.Table qualified as RQL.T.T
|
2022-04-29 05:13:13 +03:00
|
|
|
import Hasura.SQL.Backend (BackendSourceKind (..), BackendType (..))
|
2022-04-14 05:06:07 +03:00
|
|
|
import Hasura.SQL.Types (CollectableType (..))
|
2022-04-28 04:51:58 +03:00
|
|
|
import Hasura.Server.Utils qualified as HSU
|
2022-04-14 05:06:07 +03:00
|
|
|
import Hasura.Session (SessionVariable, mkSessionVariable)
|
|
|
|
import Hasura.Tracing (noReporter, runTraceTWithReporter)
|
|
|
|
import Language.GraphQL.Draft.Syntax qualified as GQL
|
|
|
|
import Network.HTTP.Client qualified as HTTP
|
|
|
|
import Witch qualified
|
2022-02-25 19:08:18 +03:00
|
|
|
|
2022-05-02 08:03:12 +03:00
|
|
|
instance BackendMetadata 'DataConnector where
|
2022-04-14 05:06:07 +03:00
|
|
|
resolveSourceConfig = resolveSourceConfig'
|
|
|
|
resolveDatabaseMetadata = resolveDatabaseMetadata'
|
|
|
|
parseBoolExpOperations = parseBoolExpOperations'
|
|
|
|
parseCollectableType = parseCollectableType'
|
2022-05-02 08:03:12 +03:00
|
|
|
buildComputedFieldInfo = error "buildComputedFieldInfo: not implemented for the Data Connector backend."
|
|
|
|
fetchAndValidateEnumValues = error "fetchAndValidateEnumValues: not implemented for the Data Connector backend."
|
|
|
|
buildFunctionInfo = error "buildFunctionInfo: not implemented for the Data Connector backend."
|
|
|
|
updateColumnInEventTrigger = error "updateColumnInEventTrigger: not implemented for the Data Connector backend."
|
|
|
|
postDropSourceHook = error "postDropSourceHook: not implemented for the Data Connector backend."
|
2022-04-14 05:06:07 +03:00
|
|
|
|
|
|
|
resolveSourceConfig' ::
|
|
|
|
MonadIO m =>
|
|
|
|
SourceName ->
|
2022-05-02 08:03:12 +03:00
|
|
|
DC.ConnSourceConfig ->
|
|
|
|
BackendSourceKind 'DataConnector ->
|
|
|
|
DC.DataConnectorBackendConfig ->
|
2022-04-14 05:06:07 +03:00
|
|
|
Environment ->
|
2022-05-02 08:03:12 +03:00
|
|
|
m (Either QErr DC.SourceConfig)
|
|
|
|
resolveSourceConfig' _sourceName (ConnSourceConfig config) (DataConnectorKind dataConnectorName) backendConfig _ = runExceptT do
|
|
|
|
DC.DataConnectorOptions {..} <-
|
2022-04-29 05:13:13 +03:00
|
|
|
OMap.lookup dataConnectorName backendConfig
|
|
|
|
`onNothing` throw400 DataConnectorError ("Data connector named " <> toTxt dataConnectorName <> " was not found in the data connector backend config")
|
2022-04-14 05:06:07 +03:00
|
|
|
manager <- liftIO $ HTTP.newManager HTTP.defaultManagerSettings
|
2022-04-29 05:13:13 +03:00
|
|
|
API.Routes {..} <- liftIO $ Agent.Client.client manager _dcoUri
|
2022-05-02 02:01:11 +03:00
|
|
|
schemaResponse <- runTraceTWithReporter noReporter "resolve source" $ _schema config
|
2022-04-14 05:06:07 +03:00
|
|
|
pure
|
2022-05-02 08:03:12 +03:00
|
|
|
DC.SourceConfig
|
2022-04-29 05:13:13 +03:00
|
|
|
{ _scEndpoint = _dcoUri,
|
2022-05-02 02:01:11 +03:00
|
|
|
_scConfig = config,
|
2022-04-29 05:13:13 +03:00
|
|
|
_scSchema = schemaResponse,
|
|
|
|
_scManager = manager
|
2022-04-14 05:06:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
resolveDatabaseMetadata' ::
|
|
|
|
Applicative m =>
|
2022-05-02 08:03:12 +03:00
|
|
|
SourceMetadata 'DataConnector ->
|
|
|
|
DC.SourceConfig ->
|
2022-04-14 05:06:07 +03:00
|
|
|
SourceTypeCustomization ->
|
2022-05-02 08:03:12 +03:00
|
|
|
m (Either QErr (ResolvedSource 'DataConnector))
|
|
|
|
resolveDatabaseMetadata' _ sc@(DC.SourceConfig {_scSchema = API.SchemaResponse {..}}) customization =
|
2022-04-14 05:06:07 +03:00
|
|
|
let tables = Map.fromList $ do
|
|
|
|
API.TableInfo {..} <- srTables
|
|
|
|
let meta =
|
2022-04-28 04:51:58 +03:00
|
|
|
RQL.T.T.DBTableMetadata
|
2022-04-14 05:06:07 +03:00
|
|
|
{ _ptmiOid = OID 0,
|
|
|
|
_ptmiColumns = do
|
|
|
|
API.ColumnInfo {..} <- dtiColumns
|
|
|
|
pure $
|
2022-04-28 04:51:58 +03:00
|
|
|
RQL.T.C.RawColumnInfo
|
2022-04-14 05:06:07 +03:00
|
|
|
{ rciName = Witch.from dciName,
|
|
|
|
rciPosition = 1,
|
|
|
|
rciType = Witch.from dciType,
|
|
|
|
rciIsNullable = dciNullable,
|
|
|
|
rciDescription = fmap GQL.Description dciDescription,
|
|
|
|
-- TODO: Add Column Mutability to the 'TableInfo'
|
2022-04-28 04:51:58 +03:00
|
|
|
rciMutability = RQL.T.C.ColumnMutability False False
|
2022-04-14 05:06:07 +03:00
|
|
|
},
|
2022-04-28 04:51:58 +03:00
|
|
|
_ptmiPrimaryKey = dtiPrimaryKey <&> \key -> RQL.T.T.PrimaryKey (RQL.T.T.Constraint () (OID 0)) (NESeq.singleton (coerce key)),
|
2022-04-14 05:06:07 +03:00
|
|
|
_ptmiUniqueConstraints = mempty,
|
|
|
|
_ptmiForeignKeys = mempty,
|
2022-04-28 04:51:58 +03:00
|
|
|
_ptmiViewInfo = Just $ RQL.T.T.ViewInfo False False False,
|
2022-04-14 05:06:07 +03:00
|
|
|
_ptmiDescription = fmap PGDescription dtiDescription,
|
|
|
|
_ptmiExtraTableMetadata = ()
|
|
|
|
}
|
|
|
|
pure (coerce dtiName, meta)
|
|
|
|
in pure $
|
|
|
|
pure $
|
|
|
|
ResolvedSource
|
|
|
|
{ _rsConfig = sc,
|
|
|
|
_rsCustomization = customization,
|
|
|
|
_rsTables = tables,
|
|
|
|
_rsFunctions = mempty,
|
|
|
|
_rsPgScalars = mempty
|
|
|
|
}
|
|
|
|
|
|
|
|
-- | This is needed to get permissions to work
|
|
|
|
parseBoolExpOperations' ::
|
|
|
|
forall m v.
|
|
|
|
MonadError QErr m =>
|
2022-05-02 08:03:12 +03:00
|
|
|
RQL.T.C.ValueParser 'DataConnector m v ->
|
2022-04-28 04:51:58 +03:00
|
|
|
IR.T.Name ->
|
2022-05-02 08:03:12 +03:00
|
|
|
RQL.T.T.FieldInfoMap (RQL.T.T.FieldInfo 'DataConnector) ->
|
|
|
|
RQL.T.C.ColumnReference 'DataConnector ->
|
2022-04-14 05:06:07 +03:00
|
|
|
J.Value ->
|
2022-05-02 08:03:12 +03:00
|
|
|
m [OpExpG 'DataConnector v]
|
2022-04-14 05:06:07 +03:00
|
|
|
parseBoolExpOperations' rhsParser _table _fields columnRef value =
|
2022-04-28 04:51:58 +03:00
|
|
|
withPathK (toTxt columnRef) $ parseOperations (RQL.T.C.columnReferenceType columnRef) value
|
2022-04-14 05:06:07 +03:00
|
|
|
where
|
|
|
|
parseWithTy ty = rhsParser (CollectableTypeScalar ty)
|
|
|
|
|
2022-05-02 08:03:12 +03:00
|
|
|
parseOperations :: RQL.T.C.ColumnType 'DataConnector -> J.Value -> m [OpExpG 'DataConnector v]
|
2022-04-14 05:06:07 +03:00
|
|
|
parseOperations columnType = \case
|
2022-04-28 04:51:58 +03:00
|
|
|
J.Object o -> traverse (parseOperation columnType) $ Map.toList o
|
2022-04-14 05:06:07 +03:00
|
|
|
v -> pure . AEQ False <$> parseWithTy columnType v
|
|
|
|
|
2022-05-02 08:03:12 +03:00
|
|
|
parseOperation :: RQL.T.C.ColumnType 'DataConnector -> (Text, J.Value) -> m (OpExpG 'DataConnector v)
|
2022-04-14 05:06:07 +03:00
|
|
|
parseOperation columnType (opStr, val) = withPathK opStr $
|
|
|
|
case opStr of
|
|
|
|
"_eq" -> parseEq
|
|
|
|
"$eq" -> parseEq
|
|
|
|
"_neq" -> parseNeq
|
|
|
|
"$neq" -> parseNeq
|
|
|
|
"_gt" -> parseGt
|
|
|
|
"$gt" -> parseGt
|
|
|
|
"_lt" -> parseLt
|
|
|
|
"$lt" -> parseLt
|
|
|
|
"_gte" -> parseGte
|
|
|
|
"$gte" -> parseGte
|
|
|
|
"_lte" -> parseLte
|
|
|
|
"$lte" -> parseLte
|
2022-04-28 04:51:58 +03:00
|
|
|
"$in" -> parseIn
|
|
|
|
"_in" -> parseIn
|
|
|
|
"$nin" -> parseNin
|
|
|
|
"_nin" -> parseNin
|
2022-04-14 05:06:07 +03:00
|
|
|
-- "$like" -> parseLike
|
|
|
|
-- "_like" -> parseLike
|
|
|
|
--
|
|
|
|
-- "$nlike" -> parseNlike
|
|
|
|
-- "_nlike" -> parseNlike
|
|
|
|
|
|
|
|
x -> throw400 UnexpectedPayload $ "Unknown operator : " <> x
|
|
|
|
where
|
2022-04-28 04:51:58 +03:00
|
|
|
colTy = RQL.T.C.columnReferenceType columnRef
|
2022-04-14 05:06:07 +03:00
|
|
|
|
|
|
|
parseOne = parseWithTy columnType val
|
2022-04-28 04:51:58 +03:00
|
|
|
parseManyWithType ty = rhsParser (CollectableTypeArray ty) val
|
2022-04-14 05:06:07 +03:00
|
|
|
|
|
|
|
parseEq = AEQ False <$> parseOne
|
|
|
|
parseNeq = ANE False <$> parseOne
|
2022-04-28 04:51:58 +03:00
|
|
|
parseIn = AIN <$> parseManyWithType colTy
|
|
|
|
parseNin = ANIN <$> parseManyWithType colTy
|
2022-04-14 05:06:07 +03:00
|
|
|
parseGt = AGT <$> parseOne
|
|
|
|
parseLt = ALT <$> parseOne
|
|
|
|
parseGte = AGTE <$> parseOne
|
|
|
|
parseLte = ALTE <$> parseOne
|
|
|
|
|
|
|
|
parseCollectableType' ::
|
|
|
|
MonadError QErr m =>
|
2022-05-02 08:03:12 +03:00
|
|
|
CollectableType (RQL.T.C.ColumnType 'DataConnector) ->
|
2022-04-14 05:06:07 +03:00
|
|
|
J.Value ->
|
2022-05-02 08:03:12 +03:00
|
|
|
m (PartialSQLExp 'DataConnector)
|
2022-04-14 05:06:07 +03:00
|
|
|
parseCollectableType' collectableType = \case
|
|
|
|
J.String t
|
2022-04-28 04:51:58 +03:00
|
|
|
| HSU.isSessionVariable t -> pure $ mkTypedSessionVar collectableType $ mkSessionVariable t
|
|
|
|
| HSU.isReqUserId t -> pure $ mkTypedSessionVar collectableType HSU.userIdHeader
|
2022-04-14 05:06:07 +03:00
|
|
|
val -> case collectableType of
|
|
|
|
CollectableTypeScalar scalarType ->
|
2022-04-28 04:51:58 +03:00
|
|
|
PSESQLExp . IR.E.Literal <$> RQL.T.C.parseScalarValueColumnType scalarType val
|
2022-04-14 05:06:07 +03:00
|
|
|
CollectableTypeArray _ ->
|
2022-05-02 08:03:12 +03:00
|
|
|
throw400 NotSupported "Array types are not supported by the Data Connector backend"
|
2022-04-14 05:06:07 +03:00
|
|
|
|
|
|
|
mkTypedSessionVar ::
|
2022-05-02 08:03:12 +03:00
|
|
|
CollectableType (RQL.T.C.ColumnType 'DataConnector) ->
|
2022-04-14 05:06:07 +03:00
|
|
|
SessionVariable ->
|
2022-05-02 08:03:12 +03:00
|
|
|
PartialSQLExp 'DataConnector
|
2022-04-14 05:06:07 +03:00
|
|
|
mkTypedSessionVar columnType =
|
|
|
|
PSESessVar (columnTypeToScalarType <$> columnType)
|
|
|
|
|
2022-05-02 08:03:12 +03:00
|
|
|
columnTypeToScalarType :: RQL.T.C.ColumnType 'DataConnector -> IR.S.T.Type
|
2022-04-14 05:06:07 +03:00
|
|
|
columnTypeToScalarType = \case
|
2022-04-28 04:51:58 +03:00
|
|
|
RQL.T.C.ColumnScalar scalarType -> scalarType
|
|
|
|
-- NOTE: This should be unreachable:
|
|
|
|
RQL.T.C.ColumnEnumReference _ -> IR.S.T.String
|