2021-05-21 05:46:58 +03:00
|
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
2021-04-12 13:18:29 +03:00
|
|
|
|
|
|
|
module Hasura.Backends.BigQuery.DDL.Source
|
|
|
|
( resolveSource,
|
|
|
|
postDropSourceHook,
|
|
|
|
resolveSourceConfig,
|
2022-05-25 13:24:41 +03:00
|
|
|
restTypeToScalarType,
|
2021-04-12 13:18:29 +03:00
|
|
|
)
|
|
|
|
where
|
|
|
|
|
2021-07-13 18:49:19 +03:00
|
|
|
import Data.Aeson qualified as J
|
2021-06-25 16:35:39 +03:00
|
|
|
import Data.ByteString.Lazy qualified as L
|
2021-06-15 18:05:41 +03:00
|
|
|
import Data.Environment qualified as Env
|
2022-05-04 17:52:29 +03:00
|
|
|
import Data.HashMap.Strict.Extended qualified as HM
|
2022-01-17 13:01:25 +03:00
|
|
|
import Data.Int qualified as Int
|
2021-06-15 18:05:41 +03:00
|
|
|
import Data.Text qualified as T
|
2021-06-25 16:35:39 +03:00
|
|
|
import Data.Text.Encoding qualified as T
|
2021-04-12 13:18:29 +03:00
|
|
|
import Data.Time.Clock.System
|
|
|
|
import Hasura.Backends.BigQuery.Connection
|
|
|
|
import Hasura.Backends.BigQuery.Meta
|
|
|
|
import Hasura.Backends.BigQuery.Source
|
|
|
|
import Hasura.Backends.BigQuery.Types
|
2021-05-11 18:18:31 +03:00
|
|
|
import Hasura.Base.Error
|
2022-07-11 11:04:30 +03:00
|
|
|
import Hasura.Logging (Hasura, Logger)
|
2021-05-11 18:18:31 +03:00
|
|
|
import Hasura.Prelude
|
2022-04-29 05:13:13 +03:00
|
|
|
import Hasura.RQL.Types.Backend (BackendConfig)
|
2021-04-12 13:18:29 +03:00
|
|
|
import Hasura.RQL.Types.Column
|
|
|
|
import Hasura.RQL.Types.Common
|
2022-12-05 13:20:47 +03:00
|
|
|
import Hasura.RQL.Types.Function (FunctionOverloads (..))
|
2021-04-12 13:18:29 +03:00
|
|
|
import Hasura.RQL.Types.Source
|
|
|
|
import Hasura.RQL.Types.Table
|
|
|
|
import Hasura.SQL.Backend
|
|
|
|
|
2022-01-17 13:01:25 +03:00
|
|
|
defaultGlobalSelectLimit :: Int.Int64
|
2021-07-19 14:39:22 +03:00
|
|
|
defaultGlobalSelectLimit = 1000
|
|
|
|
|
2022-02-14 12:45:46 +03:00
|
|
|
defaultRetryLimit :: Int
|
|
|
|
defaultRetryLimit = 5
|
|
|
|
|
|
|
|
defaultRetryBaseDelay :: Microseconds
|
|
|
|
defaultRetryBaseDelay = 500000
|
|
|
|
|
2021-09-23 15:37:56 +03:00
|
|
|
resolveSourceConfig ::
|
|
|
|
MonadIO m =>
|
2022-07-11 11:04:30 +03:00
|
|
|
Logger Hasura ->
|
2021-09-23 15:37:56 +03:00
|
|
|
SourceName ->
|
|
|
|
BigQueryConnSourceConfig ->
|
2022-04-29 05:13:13 +03:00
|
|
|
BackendSourceKind 'BigQuery ->
|
|
|
|
BackendConfig 'BigQuery ->
|
2021-09-23 15:37:56 +03:00
|
|
|
Env.Environment ->
|
2022-07-27 10:18:36 +03:00
|
|
|
manager ->
|
2021-09-23 15:37:56 +03:00
|
|
|
m (Either QErr BigQuerySourceConfig)
|
2022-07-27 10:18:36 +03:00
|
|
|
resolveSourceConfig _logger _name BigQueryConnSourceConfig {..} _backendKind _backendConfig env _manager = runExceptT $ do
|
2021-04-12 13:18:29 +03:00
|
|
|
eSA <- resolveConfigurationJson env _cscServiceAccount
|
|
|
|
case eSA of
|
|
|
|
Left e -> throw400 Unexpected $ T.pack e
|
2022-02-09 18:26:14 +03:00
|
|
|
Right serviceAccount -> do
|
2022-12-16 16:17:41 +03:00
|
|
|
projectId <- BigQueryProjectId <$> resolveConfigurationInput env _cscProjectId
|
2022-02-14 12:45:46 +03:00
|
|
|
retryOptions <- do
|
|
|
|
numRetries <-
|
|
|
|
resolveConfigurationInput env `mapM` _cscRetryLimit >>= \case
|
|
|
|
Nothing -> pure defaultRetryLimit
|
|
|
|
Just v -> readNonNegative v "retry limit"
|
|
|
|
if numRetries == 0
|
|
|
|
then pure Nothing
|
|
|
|
else do
|
|
|
|
let _retryNumRetries = numRetries
|
|
|
|
_retryBaseDelay <-
|
|
|
|
resolveConfigurationInput env `mapM` _cscRetryBaseDelay >>= \case
|
|
|
|
Nothing -> pure defaultRetryBaseDelay
|
|
|
|
Just v -> fromInteger <$> readNonNegative v "retry base delay"
|
|
|
|
pure $ Just RetryOptions {..}
|
|
|
|
_scConnection <- initConnection serviceAccount projectId retryOptions
|
2022-12-16 16:17:41 +03:00
|
|
|
_scDatasets <- fmap BigQueryDataset <$> resolveConfigurationInputs env _cscDatasets
|
2021-07-19 14:39:22 +03:00
|
|
|
_scGlobalSelectLimit <-
|
|
|
|
resolveConfigurationInput env `mapM` _cscGlobalSelectLimit >>= \case
|
|
|
|
Nothing -> pure defaultGlobalSelectLimit
|
2022-02-14 12:45:46 +03:00
|
|
|
Just v -> readNonNegative v "global select limit"
|
2022-02-09 18:26:14 +03:00
|
|
|
pure BigQuerySourceConfig {..}
|
2021-04-12 13:18:29 +03:00
|
|
|
|
2022-02-14 12:45:46 +03:00
|
|
|
readNonNegative :: (MonadError QErr m, Num a, Ord a, J.FromJSON a, Read a) => Text -> Text -> m a
|
|
|
|
readNonNegative i paramName =
|
|
|
|
-- This works around the inconsistency between JSON and
|
|
|
|
-- environment variables. The config handling module should be
|
|
|
|
-- reworked to handle non-text values better.
|
|
|
|
case readMaybe (T.unpack i) <|> J.decode (L.fromStrict (T.encodeUtf8 i)) of
|
|
|
|
Nothing -> throw400 Unexpected $ "Need a non-negative integer for " <> paramName
|
|
|
|
Just i' -> do
|
|
|
|
when (i' < 0) $ throw400 Unexpected $ "Need the integer for the " <> paramName <> " to be non-negative"
|
|
|
|
pure i'
|
|
|
|
|
2021-04-12 13:18:29 +03:00
|
|
|
resolveSource ::
|
|
|
|
(MonadIO m) =>
|
|
|
|
BigQuerySourceConfig ->
|
2023-01-20 17:51:11 +03:00
|
|
|
m (Either QErr (DBObjectsIntrospection 'BigQuery))
|
|
|
|
resolveSource sourceConfig =
|
2021-04-12 13:18:29 +03:00
|
|
|
runExceptT $ do
|
2022-05-04 17:52:29 +03:00
|
|
|
tables <- getTables sourceConfig
|
|
|
|
routines <- getRoutines sourceConfig
|
|
|
|
let result = (,) <$> tables <*> routines
|
2021-04-12 13:18:29 +03:00
|
|
|
case result of
|
|
|
|
Left err ->
|
|
|
|
throw400 Unexpected $
|
|
|
|
"unexpected exception while connecting to database: " <> tshow err
|
2022-05-04 17:52:29 +03:00
|
|
|
Right (restTables, restRoutines) -> do
|
2021-04-12 13:18:29 +03:00
|
|
|
seconds <- liftIO $ fmap systemSeconds getSystemTime
|
2022-12-05 13:20:47 +03:00
|
|
|
let functions = FunctionOverloads <$> HM.groupOnNE (routineReferenceToFunctionName . routineReference) restRoutines
|
2021-04-12 13:18:29 +03:00
|
|
|
pure
|
2023-01-20 17:51:11 +03:00
|
|
|
( DBObjectsIntrospection
|
|
|
|
{ _rsTables =
|
2021-04-12 13:18:29 +03:00
|
|
|
HM.fromList
|
|
|
|
[ ( restTableReferenceToTableName tableReference,
|
|
|
|
DBTableMetadata
|
|
|
|
{ _ptmiOid = OID (fromIntegral seconds + index :: Int), -- TODO: The seconds are used for uniqueness. BigQuery doesn't support a "stable" ID for a table.
|
|
|
|
_ptmiColumns =
|
|
|
|
[ RawColumnInfo
|
2022-01-19 11:37:50 +03:00
|
|
|
{ rciName = ColumnName name,
|
|
|
|
rciPosition = position,
|
|
|
|
rciType = restTypeToScalarType type',
|
|
|
|
rciIsNullable =
|
2021-04-12 13:18:29 +03:00
|
|
|
case mode of
|
|
|
|
Nullable -> True
|
|
|
|
_ -> False,
|
2022-01-19 11:37:50 +03:00
|
|
|
rciDescription = Nothing,
|
|
|
|
rciMutability = ColumnMutability {_cmIsInsertable = True, _cmIsUpdatable = True}
|
2021-04-12 13:18:29 +03:00
|
|
|
}
|
|
|
|
| (position, RestFieldSchema {name, type', mode}) <-
|
|
|
|
zip [1 ..] fields -- TODO: Same trouble as Oid above.
|
|
|
|
],
|
|
|
|
_ptmiPrimaryKey = Nothing,
|
|
|
|
_ptmiUniqueConstraints = mempty,
|
|
|
|
_ptmiForeignKeys = mempty,
|
|
|
|
_ptmiViewInfo = Just $ ViewInfo False False False,
|
|
|
|
_ptmiDescription = Nothing,
|
2021-05-21 05:46:58 +03:00
|
|
|
_ptmiExtraTableMetadata = ()
|
2021-04-12 13:18:29 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
| (index, RestTable {tableReference, schema}) <-
|
|
|
|
zip [0 ..] restTables,
|
|
|
|
let RestTableSchema fields = schema
|
|
|
|
],
|
2022-05-04 17:52:29 +03:00
|
|
|
_rsFunctions = functions,
|
Move, document, and prune action types and custom types types.
### Description
This PR is a first step in a series of cleanups of action relationships. This first step does not contain any behavioral change, and it simply reorganizes / prunes / rearranges / documents the code. Mainly:
- it divides some files in RQL.Types between metadata types, schema cache types, execution types;
- it renames some types for consistency;
- it minimizes exports and prunes unnecessary types;
- it moves some types in places where they make more sense;
- it replaces uses of `DMap BackendTag` with `BackendMap`.
Most of the "movement" within files re-organizes declarations in a "top-down" fashion, by moving all TH splices to the end of the file, which avoids order or declarations mattering.
### Optional list types
One main type change this PR makes is a replacement of variant list types in `CustomTypes.hs`; we had `Maybe [a]`, or sometimes `Maybe (NonEmpty a)`. This PR harmonizes all of them to `[a]`, as most of the code would use them as such, by doing `fromMaybe []` or `maybe [] toList`.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4613
GitOrigin-RevId: bc624e10df587eba862ff27a5e8021b32d0d78a2
2022-06-07 18:43:34 +03:00
|
|
|
_rsScalars = mempty
|
2021-04-12 13:18:29 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
restTypeToScalarType :: RestType -> ScalarType
|
|
|
|
restTypeToScalarType =
|
|
|
|
\case
|
|
|
|
STRING -> StringScalarType
|
|
|
|
BYTES -> BytesScalarType
|
|
|
|
INTEGER -> IntegerScalarType
|
|
|
|
FLOAT -> FloatScalarType
|
|
|
|
BOOL -> BoolScalarType
|
|
|
|
TIMESTAMP -> TimestampScalarType
|
|
|
|
DATE -> DateScalarType
|
|
|
|
TIME -> TimeScalarType
|
|
|
|
DATETIME -> DatetimeScalarType
|
|
|
|
GEOGRAPHY -> GeographyScalarType
|
|
|
|
STRUCT -> StructScalarType
|
|
|
|
BIGDECIMAL -> BigDecimalScalarType
|
|
|
|
DECIMAL -> DecimalScalarType
|
|
|
|
|
|
|
|
-- Hierarchy: Project / Dataset / Table
|
|
|
|
-- see <https://cloud.google.com/bigquery/docs/datasets-intro>
|
|
|
|
restTableReferenceToTableName :: RestTableReference -> TableName
|
|
|
|
restTableReferenceToTableName RestTableReference {..} =
|
|
|
|
TableName {tableName = tableId, tableNameSchema = datasetId}
|
|
|
|
|
|
|
|
-- We ignore project id and push that requirement up to the top to
|
|
|
|
-- the data source level.
|
2021-09-24 01:56:37 +03:00
|
|
|
|
2021-04-12 13:18:29 +03:00
|
|
|
postDropSourceHook ::
|
|
|
|
(MonadIO m) =>
|
|
|
|
BigQuerySourceConfig ->
|
2022-07-19 14:39:44 +03:00
|
|
|
TableEventTriggers 'BigQuery ->
|
2021-04-12 13:18:29 +03:00
|
|
|
m ()
|
2022-07-19 14:39:44 +03:00
|
|
|
postDropSourceHook _ _ =
|
2021-04-12 13:18:29 +03:00
|
|
|
-- On BigQuery we don't keep connections open.
|
|
|
|
pure ()
|