{-# OPTIONS_GHC -fno-warn-orphans #-}

module Hasura.Backends.BigQuery.Instances.Execute () where

import Data.Aeson qualified as J
import Data.Aeson.Text qualified as J
import Data.Environment qualified as Env
import Data.HashMap.Strict qualified as HashMap
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
import Data.Text qualified as T
import Data.Text.Lazy qualified as LT
import Data.Text.Lazy.Builder qualified as LT
import Data.Vector qualified as V
import Hasura.Backends.BigQuery.Execute qualified as DataLoader
import Hasura.Backends.BigQuery.FromIr qualified as BigQuery
import Hasura.Backends.BigQuery.Plan
import Hasura.Backends.BigQuery.ToQuery qualified as ToQuery
import Hasura.Backends.BigQuery.Types qualified as BigQuery
import Hasura.Base.Error
import Hasura.Base.Error qualified as E
import Hasura.EncJSON
import Hasura.Function.Cache
import Hasura.GraphQL.Execute.Backend
import Hasura.GraphQL.Namespace (RootFieldAlias)
import Hasura.GraphQL.Parser.Variable qualified as G
import Hasura.Logging qualified as L
import Hasura.Prelude
import Hasura.QueryTags
  ( emptyQueryTagsComment,
  )
import Hasura.RQL.IR
import Hasura.RQL.IR.Select qualified as IR
import Hasura.RQL.IR.Value qualified as IR
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.BackendType
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Schema.Options qualified as Options
import Hasura.SQL.AnyBackend qualified as AB
import Hasura.Session
import Language.GraphQL.Draft.Syntax qualified as G
import Network.HTTP.Client as HTTP
import Network.HTTP.Types qualified as HTTP

instance BackendExecute 'BigQuery where
  type PreparedQuery 'BigQuery = Text
  type MultiplexedQuery 'BigQuery = Void
  type ExecutionMonad 'BigQuery = IdentityT

  mkDBQueryPlan :: forall (m :: * -> *).
(MonadError QErr m, MonadQueryTags m,
 MonadReader QueryTagsComment m) =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (DBStepInfo 'BigQuery)
mkDBQueryPlan = UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (DBStepInfo 'BigQuery)
forall (m :: * -> *).
MonadError QErr m =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (DBStepInfo 'BigQuery)
bqDBQueryPlan
  mkDBMutationPlan :: forall (m :: * -> *).
(MonadError QErr m, MonadIO m, MonadQueryTags m,
 MonadReader QueryTagsComment m, MonadTrace m) =>
Environment
-> Manager
-> Logger Hasura
-> UserInfo
-> StringifyNumbers
-> SourceName
-> SourceConfig 'BigQuery
-> MutationDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> Maybe (HashMap Name (Value Variable))
-> m (DBStepInfo 'BigQuery)
mkDBMutationPlan = Environment
-> Manager
-> Logger Hasura
-> UserInfo
-> StringifyNumbers
-> SourceName
-> SourceConfig 'BigQuery
-> MutationDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> Maybe (HashMap Name (Value Variable))
-> m (DBStepInfo 'BigQuery)
forall (m :: * -> *).
MonadError QErr m =>
Environment
-> Manager
-> Logger Hasura
-> UserInfo
-> StringifyNumbers
-> SourceName
-> SourceConfig 'BigQuery
-> MutationDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> Maybe (HashMap Name (Value Variable))
-> m (DBStepInfo 'BigQuery)
bqDBMutationPlan
  mkLiveQuerySubscriptionPlan :: forall (m :: * -> *).
(MonadError QErr m, MonadIO m, MonadBaseControl IO m,
 MonadReader QueryTagsComment m) =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> Maybe Name
-> RootFieldMap
     (QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery))
-> [Header]
-> Maybe Name
-> m (SubscriptionQueryPlan 'BigQuery (MultiplexedQuery 'BigQuery))
mkLiveQuerySubscriptionPlan UserInfo
_ SourceName
_ SourceConfig 'BigQuery
_ Maybe Name
_ RootFieldMap (QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery))
_ [Header]
_ Maybe Name
_ =
    Text -> m (SubscriptionQueryPlan 'BigQuery Void)
forall (m :: * -> *) a. QErrM m => Text -> m a
throw500 Text
"Cannot currently perform subscriptions on BigQuery sources."
  mkDBStreamingSubscriptionPlan :: forall (m :: * -> *).
(MonadError QErr m, MonadIO m, MonadBaseControl IO m,
 MonadReader QueryTagsComment m) =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> (RootFieldAlias,
    QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery))
-> [Header]
-> Maybe Name
-> m (SubscriptionQueryPlan 'BigQuery (MultiplexedQuery 'BigQuery))
mkDBStreamingSubscriptionPlan UserInfo
_ SourceName
_ SourceConfig 'BigQuery
_ (RootFieldAlias,
 QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery))
_ [Header]
_ Maybe Name
_ =
    Text -> m (SubscriptionQueryPlan 'BigQuery Void)
forall (m :: * -> *) a. QErrM m => Text -> m a
throw500 Text
"Cannot currently perform subscriptions on BigQuery sources."
  mkDBQueryExplain :: forall (m :: * -> *).
MonadError QErr m =>
RootFieldAlias
-> UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (AnyBackend DBStepInfo)
mkDBQueryExplain = RootFieldAlias
-> UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (AnyBackend DBStepInfo)
forall (m :: * -> *).
MonadError QErr m =>
RootFieldAlias
-> UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (AnyBackend DBStepInfo)
bqDBQueryExplain
  mkSubscriptionExplain :: forall (m :: * -> *).
(MonadError QErr m, MonadIO m, MonadBaseControl IO m) =>
SubscriptionQueryPlan 'BigQuery (MultiplexedQuery 'BigQuery)
-> m SubscriptionQueryPlanExplanation
mkSubscriptionExplain SubscriptionQueryPlan 'BigQuery (MultiplexedQuery 'BigQuery)
_ =
    Text -> m SubscriptionQueryPlanExplanation
forall (m :: * -> *) a. QErrM m => Text -> m a
throw500 Text
"Cannot currently retrieve query execution plans on BigQuery sources."

  -- NOTE: Currently unimplemented!.
  --
  -- This function is just a stub for future implementation; for now it just
  -- throws a 500 error.
  mkDBRemoteRelationshipPlan :: forall (m :: * -> *).
(MonadError QErr m, MonadQueryTags m) =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> NonEmpty Object
-> HashMap FieldName (Column 'BigQuery, ScalarType 'BigQuery)
-> FieldName
-> (FieldName,
    SourceRelationshipSelection 'BigQuery Void UnpreparedValue)
-> [Header]
-> Maybe Name
-> StringifyNumbers
-> m (DBStepInfo 'BigQuery)
mkDBRemoteRelationshipPlan =
    UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> NonEmpty Object
-> HashMap FieldName (Column 'BigQuery, ScalarType 'BigQuery)
-> FieldName
-> (FieldName,
    SourceRelationshipSelection 'BigQuery Void UnpreparedValue)
-> [Header]
-> Maybe Name
-> StringifyNumbers
-> m (DBStepInfo 'BigQuery)
forall (m :: * -> *).
MonadError QErr m =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> NonEmpty Object
-> HashMap FieldName (Column 'BigQuery, ScalarType 'BigQuery)
-> FieldName
-> (FieldName,
    SourceRelationshipSelection 'BigQuery Void UnpreparedValue)
-> [Header]
-> Maybe Name
-> StringifyNumbers
-> m (DBStepInfo 'BigQuery)
bqDBRemoteRelationshipPlan

-- query

bqDBQueryPlan ::
  forall m.
  ( MonadError E.QErr m
  ) =>
  UserInfo ->
  SourceName ->
  SourceConfig 'BigQuery ->
  QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery) ->
  [HTTP.Header] ->
  Maybe G.Name ->
  m (DBStepInfo 'BigQuery)
bqDBQueryPlan :: forall (m :: * -> *).
MonadError QErr m =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (DBStepInfo 'BigQuery)
bqDBQueryPlan UserInfo
userInfo SourceName
sourceName SourceConfig 'BigQuery
sourceConfig QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
qrf [Header]
_ Maybe Name
_ = do
  -- TODO (naveen): Append query tags to the query
  Select
select <- FromIrConfig
-> UserInfo
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> m Select
forall (m :: * -> *).
MonadError QErr m =>
FromIrConfig
-> UserInfo
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> m Select
planNoPlan (BigQuerySourceConfig -> FromIrConfig
BigQuery.bigQuerySourceConfigToFromIrConfig BigQuerySourceConfig
SourceConfig 'BigQuery
sourceConfig) UserInfo
userInfo QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
qrf
  let action :: OnBaseMonad IdentityT (ActionResult 'BigQuery)
action = (forall (m :: * -> *).
 (Functor (IdentityT m), MonadIO m, MonadBaseControl IO m,
  MonadTrace m, MonadError QErr m) =>
 IdentityT m (ActionResult 'BigQuery))
-> OnBaseMonad IdentityT (ActionResult 'BigQuery)
forall (t :: (* -> *) -> * -> *) a.
(forall (m :: * -> *).
 (Functor (t m), MonadIO m, MonadBaseControl IO m, MonadTrace m,
  MonadError QErr m) =>
 t m a)
-> OnBaseMonad t a
OnBaseMonad do
        Either ExecuteProblem (Job, RecordSet)
result <-
          BigQuerySourceConfig
-> Execute (Job, RecordSet)
-> IdentityT m (Either ExecuteProblem (Job, RecordSet))
forall (m :: * -> *).
MonadIO m =>
BigQuerySourceConfig
-> Execute (Job, RecordSet)
-> m (Either ExecuteProblem (Job, RecordSet))
DataLoader.runExecute
            BigQuerySourceConfig
SourceConfig 'BigQuery
sourceConfig
            (Select -> Execute (Job, RecordSet)
DataLoader.executeSelect Select
select)
        case Either ExecuteProblem (Job, RecordSet)
result of
          Left ExecuteProblem
err -> Text -> Value -> IdentityT m (ActionResult 'BigQuery)
forall (m :: * -> *) a. QErrM m => Text -> Value -> m a
throw500WithDetail (ShowDetails -> ExecuteProblem -> Text
DataLoader.executeProblemMessage ShowDetails
DataLoader.HideDetails ExecuteProblem
err) (Value -> IdentityT m (ActionResult 'BigQuery))
-> Value -> IdentityT m (ActionResult 'BigQuery)
forall a b. (a -> b) -> a -> b
$ ExecuteProblem -> Value
forall a. ToJSON a => a -> Value
J.toJSON ExecuteProblem
err
          Right (Job
job, RecordSet
recordSet) -> ActionResult 'BigQuery -> IdentityT m (ActionResult 'BigQuery)
forall a. a -> IdentityT m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ActionResult {arStatistics :: Maybe (ExecutionStatistics 'BigQuery)
arStatistics = ExecutionStatistics -> Maybe ExecutionStatistics
forall a. a -> Maybe a
Just BigQuery.ExecutionStatistics {$sel:_esJob:ExecutionStatistics :: Job
_esJob = Job
job}, arResult :: EncJSON
arResult = Cardinality -> RecordSet -> EncJSON
recordSetToEncJSON (Select -> Cardinality
BigQuery.selectCardinality Select
select) RecordSet
recordSet}
  DBStepInfo 'BigQuery -> m (DBStepInfo 'BigQuery)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (DBStepInfo 'BigQuery -> m (DBStepInfo 'BigQuery))
-> DBStepInfo 'BigQuery -> m (DBStepInfo 'BigQuery)
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
SourceName
-> SourceConfig b
-> Maybe (PreparedQuery b)
-> OnBaseMonad (ExecutionMonad b) (ActionResult b)
-> ResolvedConnectionTemplate b
-> DBStepInfo b
DBStepInfo @'BigQuery SourceName
sourceName SourceConfig 'BigQuery
sourceConfig (Text -> Maybe Text
forall a. a -> Maybe a
Just (Select -> Text
selectSQLTextForExplain Select
select)) OnBaseMonad IdentityT (ActionResult 'BigQuery)
OnBaseMonad (ExecutionMonad 'BigQuery) (ActionResult 'BigQuery)
action ()

-- | Convert the dataloader's 'RecordSet' type to JSON.
recordSetToEncJSON :: BigQuery.Cardinality -> DataLoader.RecordSet -> EncJSON
recordSetToEncJSON :: Cardinality -> RecordSet -> EncJSON
recordSetToEncJSON Cardinality
cardinality DataLoader.RecordSet {Vector (InsOrdHashMap FieldNameText OutputValue)
rows :: Vector (InsOrdHashMap FieldNameText OutputValue)
$sel:rows:RecordSet :: RecordSet -> Vector (InsOrdHashMap FieldNameText OutputValue)
rows} =
  case Cardinality
cardinality of
    Cardinality
BigQuery.One
      | Just InsOrdHashMap FieldNameText OutputValue
row <- Vector (InsOrdHashMap FieldNameText OutputValue)
rows Vector (InsOrdHashMap FieldNameText OutputValue)
-> Int -> Maybe (InsOrdHashMap FieldNameText OutputValue)
forall a. Vector a -> Int -> Maybe a
V.!? Int
0 -> InsOrdHashMap FieldNameText OutputValue -> EncJSON
encJFromRecord InsOrdHashMap FieldNameText OutputValue
row
      | Bool
otherwise -> [EncJSON] -> EncJSON
encJFromList (Vector EncJSON -> [EncJSON]
forall a. Vector a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList ((InsOrdHashMap FieldNameText OutputValue -> EncJSON)
-> Vector (InsOrdHashMap FieldNameText OutputValue)
-> Vector EncJSON
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap InsOrdHashMap FieldNameText OutputValue -> EncJSON
encJFromRecord Vector (InsOrdHashMap FieldNameText OutputValue)
rows))
    Cardinality
BigQuery.Many -> [EncJSON] -> EncJSON
encJFromList (Vector EncJSON -> [EncJSON]
forall a. Vector a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList ((InsOrdHashMap FieldNameText OutputValue -> EncJSON)
-> Vector (InsOrdHashMap FieldNameText OutputValue)
-> Vector EncJSON
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap InsOrdHashMap FieldNameText OutputValue -> EncJSON
encJFromRecord Vector (InsOrdHashMap FieldNameText OutputValue)
rows))
  where
    encJFromRecord :: InsOrdHashMap FieldNameText OutputValue -> EncJSON
encJFromRecord =
      InsOrdHashMap Text EncJSON -> EncJSON
encJFromInsOrdHashMap (InsOrdHashMap Text EncJSON -> EncJSON)
-> (InsOrdHashMap FieldNameText OutputValue
    -> InsOrdHashMap Text EncJSON)
-> InsOrdHashMap FieldNameText OutputValue
-> EncJSON
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (OutputValue -> EncJSON)
-> InsOrdHashMap Text OutputValue -> InsOrdHashMap Text EncJSON
forall a b.
(a -> b) -> InsOrdHashMap Text a -> InsOrdHashMap Text b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap OutputValue -> EncJSON
encJFromOutputValue (InsOrdHashMap Text OutputValue -> InsOrdHashMap Text EncJSON)
-> (InsOrdHashMap FieldNameText OutputValue
    -> InsOrdHashMap Text OutputValue)
-> InsOrdHashMap FieldNameText OutputValue
-> InsOrdHashMap Text EncJSON
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FieldNameText -> Text)
-> InsOrdHashMap FieldNameText OutputValue
-> InsOrdHashMap Text OutputValue
forall k' k v.
(Eq k', Hashable k') =>
(k -> k') -> InsOrdHashMap k v -> InsOrdHashMap k' v
InsOrdHashMap.mapKeys FieldNameText -> Text
forall a b. Coercible a b => a -> b
coerce
    encJFromOutputValue :: OutputValue -> EncJSON
encJFromOutputValue OutputValue
outputValue =
      case OutputValue
outputValue of
        OutputValue
DataLoader.NullOutputValue -> Value -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Value
J.Null
        DataLoader.DecimalOutputValue Decimal
i -> Decimal -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Decimal
i
        DataLoader.BigDecimalOutputValue BigDecimal
i -> BigDecimal -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue BigDecimal
i
        DataLoader.FloatOutputValue Float64
i -> Float64 -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Float64
i
        DataLoader.TextOutputValue Text
i -> Text -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Text
i
        DataLoader.BytesOutputValue Base64
i -> Base64 -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Base64
i
        DataLoader.DateOutputValue Date
i -> Date -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Date
i
        DataLoader.TimestampOutputValue Timestamp
i -> Timestamp -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Timestamp
i
        DataLoader.TimeOutputValue Time
i -> Time -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Time
i
        DataLoader.DatetimeOutputValue Datetime
i -> Datetime -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Datetime
i
        DataLoader.GeographyOutputValue Geography
i -> Geography -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Geography
i
        DataLoader.BoolOutputValue Bool
i -> Bool -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Bool
i
        DataLoader.IntegerOutputValue Int64
i -> Int64 -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Int64
i
        DataLoader.JsonOutputValue Value
i -> Value -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue Value
i
        DataLoader.ArrayOutputValue Vector OutputValue
vector ->
          [EncJSON] -> EncJSON
encJFromList (Vector EncJSON -> [EncJSON]
forall a. Vector a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList ((OutputValue -> EncJSON) -> Vector OutputValue -> Vector EncJSON
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap OutputValue -> EncJSON
encJFromOutputValue Vector OutputValue
vector))
        -- Really, the case below shouldn't be happening. But if it
        -- does, it's not a problem either. The output will just have
        -- a record in it.
        DataLoader.RecordOutputValue InsOrdHashMap FieldNameText OutputValue
record -> InsOrdHashMap FieldNameText OutputValue -> EncJSON
encJFromRecord InsOrdHashMap FieldNameText OutputValue
record

-- mutation

bqDBMutationPlan ::
  forall m.
  ( MonadError E.QErr m
  ) =>
  Env.Environment ->
  HTTP.Manager ->
  L.Logger L.Hasura ->
  UserInfo ->
  Options.StringifyNumbers ->
  SourceName ->
  SourceConfig 'BigQuery ->
  MutationDB 'BigQuery Void (UnpreparedValue 'BigQuery) ->
  [HTTP.Header] ->
  Maybe G.Name ->
  Maybe (HashMap G.Name (G.Value G.Variable)) ->
  m (DBStepInfo 'BigQuery)
bqDBMutationPlan :: forall (m :: * -> *).
MonadError QErr m =>
Environment
-> Manager
-> Logger Hasura
-> UserInfo
-> StringifyNumbers
-> SourceName
-> SourceConfig 'BigQuery
-> MutationDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> Maybe (HashMap Name (Value Variable))
-> m (DBStepInfo 'BigQuery)
bqDBMutationPlan Environment
_env Manager
_manager Logger Hasura
_logger UserInfo
_userInfo StringifyNumbers
_stringifyNum SourceName
_sourceName SourceConfig 'BigQuery
_sourceConfig MutationDB 'BigQuery Void (UnpreparedValue 'BigQuery)
_mrf [Header]
_headers Maybe Name
_gName Maybe (HashMap Name (Value Variable))
_maybeSelSetArgs =
  Text -> m (DBStepInfo 'BigQuery)
forall (m :: * -> *) a. QErrM m => Text -> m a
throw500 Text
"mutations are not supported in BigQuery; this should be unreachable"

-- explain

bqDBQueryExplain ::
  (MonadError E.QErr m) =>
  RootFieldAlias ->
  UserInfo ->
  SourceName ->
  SourceConfig 'BigQuery ->
  QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery) ->
  [HTTP.Header] ->
  Maybe G.Name ->
  m (AB.AnyBackend DBStepInfo)
bqDBQueryExplain :: forall (m :: * -> *).
MonadError QErr m =>
RootFieldAlias
-> UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (AnyBackend DBStepInfo)
bqDBQueryExplain RootFieldAlias
fieldName UserInfo
userInfo SourceName
sourceName SourceConfig 'BigQuery
sourceConfig QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
qrf [Header]
_ Maybe Name
_ = do
  Select
select <- FromIrConfig
-> UserInfo
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> m Select
forall (m :: * -> *).
MonadError QErr m =>
FromIrConfig
-> UserInfo
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> m Select
planNoPlan (BigQuerySourceConfig -> FromIrConfig
BigQuery.bigQuerySourceConfigToFromIrConfig BigQuerySourceConfig
SourceConfig 'BigQuery
sourceConfig) UserInfo
userInfo QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
qrf
  let textSQL :: Text
textSQL = Select -> Text
selectSQLTextForExplain Select
select
  AnyBackend DBStepInfo -> m (AnyBackend DBStepInfo)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (AnyBackend DBStepInfo -> m (AnyBackend DBStepInfo))
-> AnyBackend DBStepInfo -> m (AnyBackend DBStepInfo)
forall a b. (a -> b) -> a -> b
$ DBStepInfo 'BigQuery -> AnyBackend DBStepInfo
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
AB.mkAnyBackend
    (DBStepInfo 'BigQuery -> AnyBackend DBStepInfo)
-> DBStepInfo 'BigQuery -> AnyBackend DBStepInfo
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
SourceName
-> SourceConfig b
-> Maybe (PreparedQuery b)
-> OnBaseMonad (ExecutionMonad b) (ActionResult b)
-> ResolvedConnectionTemplate b
-> DBStepInfo b
DBStepInfo @'BigQuery
      SourceName
sourceName
      SourceConfig 'BigQuery
sourceConfig
      Maybe Text
Maybe (PreparedQuery 'BigQuery)
forall a. Maybe a
Nothing
      ( (forall (m :: * -> *).
 (Functor (ExecutionMonad 'BigQuery m), MonadIO m,
  MonadBaseControl IO m, MonadTrace m, MonadError QErr m) =>
 ExecutionMonad 'BigQuery m (ActionResult 'BigQuery))
-> OnBaseMonad (ExecutionMonad 'BigQuery) (ActionResult 'BigQuery)
forall (t :: (* -> *) -> * -> *) a.
(forall (m :: * -> *).
 (Functor (t m), MonadIO m, MonadBaseControl IO m, MonadTrace m,
  MonadError QErr m) =>
 t m a)
-> OnBaseMonad t a
OnBaseMonad
          ((forall (m :: * -> *).
  (Functor (ExecutionMonad 'BigQuery m), MonadIO m,
   MonadBaseControl IO m, MonadTrace m, MonadError QErr m) =>
  ExecutionMonad 'BigQuery m (ActionResult 'BigQuery))
 -> OnBaseMonad (ExecutionMonad 'BigQuery) (ActionResult 'BigQuery))
-> (forall (m :: * -> *).
    (Functor (ExecutionMonad 'BigQuery m), MonadIO m,
     MonadBaseControl IO m, MonadTrace m, MonadError QErr m) =>
    ExecutionMonad 'BigQuery m (ActionResult 'BigQuery))
-> OnBaseMonad (ExecutionMonad 'BigQuery) (ActionResult 'BigQuery)
forall a b. (a -> b) -> a -> b
$ ActionResult 'BigQuery
-> ExecutionMonad 'BigQuery m (ActionResult 'BigQuery)
forall a. a -> ExecutionMonad 'BigQuery m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
          (ActionResult 'BigQuery
 -> ExecutionMonad 'BigQuery m (ActionResult 'BigQuery))
-> ActionResult 'BigQuery
-> ExecutionMonad 'BigQuery m (ActionResult 'BigQuery)
forall a b. (a -> b) -> a -> b
$ EncJSON -> ActionResult 'BigQuery
forall (b :: BackendType). EncJSON -> ActionResult b
withNoStatistics
          (EncJSON -> ActionResult 'BigQuery)
-> EncJSON -> ActionResult 'BigQuery
forall a b. (a -> b) -> a -> b
$ ExplainPlan -> EncJSON
forall a. ToJSON a => a -> EncJSON
encJFromJValue
          (ExplainPlan -> EncJSON) -> ExplainPlan -> EncJSON
forall a b. (a -> b) -> a -> b
$ RootFieldAlias -> Maybe Text -> Maybe [Text] -> ExplainPlan
ExplainPlan
            RootFieldAlias
fieldName
            (Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Text
textSQL)
            ([Text] -> Maybe [Text]
forall a. a -> Maybe a
Just ([Text] -> Maybe [Text]) -> [Text] -> Maybe [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines (Text -> [Text]) -> Text -> [Text]
forall a b. (a -> b) -> a -> b
$ Text
textSQL)
      )
      ()

-- | Get the SQL text for a select, with parameters left as $1, $2, .. holes.
selectSQLTextForExplain :: BigQuery.Select -> Text
selectSQLTextForExplain :: Select -> Text
selectSQLTextForExplain =
  Text -> Text
LT.toStrict
    (Text -> Text) -> (Select -> Text) -> Select -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
LT.toLazyText
    (Builder -> Text) -> (Select -> Builder) -> Select -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder, InsOrdHashMap Int TypedValue) -> Builder
forall a b. (a, b) -> a
fst
    ((Builder, InsOrdHashMap Int TypedValue) -> Builder)
-> (Select -> (Builder, InsOrdHashMap Int TypedValue))
-> Select
-> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Printer -> (Builder, InsOrdHashMap Int TypedValue)
ToQuery.renderBuilderPretty
    (Printer -> (Builder, InsOrdHashMap Int TypedValue))
-> (Select -> Printer)
-> Select
-> (Builder, InsOrdHashMap Int TypedValue)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Select -> Printer
ToQuery.fromSelect

--------------------------------------------------------------------------------
-- Remote Relationships (e.g. DB-to-DB Joins, remote schema joins, etc.)
--------------------------------------------------------------------------------

-- | Construct an action (i.e. 'DBStepInfo') which can marshal some remote
-- relationship information into a form that BigQuery can query against.
--
-- XXX: Currently unimplemented; the Postgres implementation uses
-- @jsonb_to_recordset@ to query the remote relationship, however this
-- functionality doesn't exist in BigQuery.
--
-- NOTE: The following typeclass constraints will be necessary when implementing
-- this function for real:
--
-- @
--   MonadQueryTags m
--   Backend 'BigQuery
-- @
bqDBRemoteRelationshipPlan ::
  forall m.
  ( MonadError QErr m
  ) =>
  UserInfo ->
  SourceName ->
  SourceConfig 'BigQuery ->
  -- | List of json objects, each of which becomes a row of the table.
  NonEmpty J.Object ->
  -- | The above objects have this schema
  --
  -- XXX: What is this for/what does this mean?
  HashMap FieldName (Column 'BigQuery, ScalarType 'BigQuery) ->
  -- | This is a field name from the lhs that *has* to be selected in the
  -- response along with the relationship.
  FieldName ->
  (FieldName, SourceRelationshipSelection 'BigQuery Void UnpreparedValue) ->
  [HTTP.Header] ->
  Maybe G.Name ->
  Options.StringifyNumbers ->
  m (DBStepInfo 'BigQuery)
bqDBRemoteRelationshipPlan :: forall (m :: * -> *).
MonadError QErr m =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> NonEmpty Object
-> HashMap FieldName (Column 'BigQuery, ScalarType 'BigQuery)
-> FieldName
-> (FieldName,
    SourceRelationshipSelection 'BigQuery Void UnpreparedValue)
-> [Header]
-> Maybe Name
-> StringifyNumbers
-> m (DBStepInfo 'BigQuery)
bqDBRemoteRelationshipPlan UserInfo
userInfo SourceName
sourceName SourceConfig 'BigQuery
sourceConfig NonEmpty Object
lhs HashMap FieldName (Column 'BigQuery, ScalarType 'BigQuery)
lhsSchema FieldName
argumentId (FieldName,
 SourceRelationshipSelection 'BigQuery Void UnpreparedValue)
relationship [Header]
reqHeaders Maybe Name
operationName StringifyNumbers
stringifyNumbers = do
  (ReaderT QueryTagsComment m (DBStepInfo 'BigQuery)
 -> QueryTagsComment -> m (DBStepInfo 'BigQuery))
-> QueryTagsComment
-> ReaderT QueryTagsComment m (DBStepInfo 'BigQuery)
-> m (DBStepInfo 'BigQuery)
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT QueryTagsComment m (DBStepInfo 'BigQuery)
-> QueryTagsComment -> m (DBStepInfo 'BigQuery)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT QueryTagsComment
emptyQueryTagsComment (ReaderT QueryTagsComment m (DBStepInfo 'BigQuery)
 -> m (DBStepInfo 'BigQuery))
-> ReaderT QueryTagsComment m (DBStepInfo 'BigQuery)
-> m (DBStepInfo 'BigQuery)
forall a b. (a -> b) -> a -> b
$ UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> ReaderT QueryTagsComment m (DBStepInfo 'BigQuery)
forall (m :: * -> *).
MonadError QErr m =>
UserInfo
-> SourceName
-> SourceConfig 'BigQuery
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
-> [Header]
-> Maybe Name
-> m (DBStepInfo 'BigQuery)
bqDBQueryPlan UserInfo
userInfo SourceName
sourceName SourceConfig 'BigQuery
sourceConfig QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
rootSelection [Header]
reqHeaders Maybe Name
operationName
  where
    coerceToColumn :: FieldName -> ColumnName
coerceToColumn = Text -> ColumnName
BigQuery.ColumnName (Text -> ColumnName)
-> (FieldName -> Text) -> FieldName -> ColumnName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FieldName -> Text
getFieldNameTxt
    joinColumnMapping :: HashMap ColumnName (ColumnName, ScalarType)
joinColumnMapping = (FieldName -> ColumnName)
-> HashMap FieldName (ColumnName, ScalarType)
-> HashMap ColumnName (ColumnName, ScalarType)
forall k2 k1 v.
(Eq k2, Hashable k2) =>
(k1 -> k2) -> HashMap k1 v -> HashMap k2 v
mapKeys FieldName -> ColumnName
coerceToColumn HashMap FieldName (Column 'BigQuery, ScalarType 'BigQuery)
HashMap FieldName (ColumnName, ScalarType)
lhsSchema

    rowsArgument :: UnpreparedValue 'BigQuery
    rowsArgument :: UnpreparedValue 'BigQuery
rowsArgument =
      Provenance -> ColumnValue 'BigQuery -> UnpreparedValue 'BigQuery
forall (b :: BackendType).
Provenance -> ColumnValue b -> UnpreparedValue b
UVParameter Provenance
IR.FreshVar
        (ColumnValue 'BigQuery -> UnpreparedValue 'BigQuery)
-> ColumnValue 'BigQuery -> UnpreparedValue 'BigQuery
forall a b. (a -> b) -> a -> b
$ ColumnType 'BigQuery
-> ScalarValue 'BigQuery -> ColumnValue 'BigQuery
forall (b :: BackendType).
ColumnType b -> ScalarValue b -> ColumnValue b
ColumnValue (ScalarType 'BigQuery -> ColumnType 'BigQuery
forall (b :: BackendType). ScalarType b -> ColumnType b
ColumnScalar ScalarType 'BigQuery
ScalarType
BigQuery.StringScalarType)
        (ScalarValue 'BigQuery -> ColumnValue 'BigQuery)
-> ScalarValue 'BigQuery -> ColumnValue 'BigQuery
forall a b. (a -> b) -> a -> b
$ Text -> ScalarValue 'BigQuery
Text -> Value
BigQuery.StringValue
        (Text -> ScalarValue 'BigQuery)
-> (Text -> Text) -> Text -> ScalarValue 'BigQuery
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
LT.toStrict
        (Text -> ScalarValue 'BigQuery) -> Text -> ScalarValue 'BigQuery
forall a b. (a -> b) -> a -> b
$ NonEmpty Object -> Text
forall a. ToJSON a => a -> Text
J.encodeToLazyText NonEmpty Object
lhs

    recordSetDefinitionList :: [(ColumnName, ScalarType)]
recordSetDefinitionList =
      (FieldName -> ColumnName
coerceToColumn FieldName
argumentId, ScalarType
BigQuery.IntegerScalarType) (ColumnName, ScalarType)
-> [(ColumnName, ScalarType)] -> [(ColumnName, ScalarType)]
forall a. a -> [a] -> [a]
: HashMap ColumnName ScalarType -> [(ColumnName, ScalarType)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList (((ColumnName, ScalarType) -> ScalarType)
-> HashMap ColumnName (ColumnName, ScalarType)
-> HashMap ColumnName ScalarType
forall a b.
(a -> b) -> HashMap ColumnName a -> HashMap ColumnName b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ColumnName, ScalarType) -> ScalarType
forall a b. (a, b) -> b
snd HashMap ColumnName (ColumnName, ScalarType)
joinColumnMapping)

    jsonToRecordSet :: IR.SelectFromG ('BigQuery) (UnpreparedValue 'BigQuery)
    jsonToRecordSet :: SelectFromG 'BigQuery (UnpreparedValue 'BigQuery)
jsonToRecordSet =
      FunctionName 'BigQuery
-> FunctionArgsExp 'BigQuery (UnpreparedValue 'BigQuery)
-> Maybe [(Column 'BigQuery, ScalarType 'BigQuery)]
-> SelectFromG 'BigQuery (UnpreparedValue 'BigQuery)
forall (b :: BackendType) v.
FunctionName b
-> FunctionArgsExp b v
-> Maybe [(Column b, ScalarType b)]
-> SelectFromG b v
IR.FromFunction
        (Text -> Maybe Text -> FunctionName
BigQuery.FunctionName Text
"unnest" Maybe Text
forall a. Maybe a
Nothing)
        ( [ArgumentExp (UnpreparedValue 'BigQuery)]
-> HashMap Text (ArgumentExp (UnpreparedValue 'BigQuery))
-> FunctionArgsExpG (ArgumentExp (UnpreparedValue 'BigQuery))
forall a. [a] -> HashMap Text a -> FunctionArgsExpG a
FunctionArgsExp
            [UnpreparedValue 'BigQuery
-> ArgumentExp (UnpreparedValue 'BigQuery)
forall v. v -> ArgumentExp v
BigQuery.AEInput UnpreparedValue 'BigQuery
rowsArgument]
            HashMap Text (ArgumentExp (UnpreparedValue 'BigQuery))
forall a. Monoid a => a
mempty
        )
        ([(ColumnName, ScalarType)] -> Maybe [(ColumnName, ScalarType)]
forall a. a -> Maybe a
Just [(ColumnName, ScalarType)]
recordSetDefinitionList)

    rootSelection :: QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
rootSelection =
      HashMap (Column 'BigQuery) (Column 'BigQuery)
-> SelectFromG 'BigQuery (UnpreparedValue 'BigQuery)
-> Column 'BigQuery
-> ColumnType 'BigQuery
-> (FieldName,
    SourceRelationshipSelection 'BigQuery Void UnpreparedValue)
-> StringifyNumbers
-> QueryDB 'BigQuery Void (UnpreparedValue 'BigQuery)
forall (b :: BackendType).
Backend b =>
HashMap (Column b) (Column b)
-> SelectFromG b (UnpreparedValue b)
-> Column b
-> ColumnType b
-> (FieldName, SourceRelationshipSelection b Void UnpreparedValue)
-> StringifyNumbers
-> QueryDB b Void (UnpreparedValue b)
convertRemoteSourceRelationship
        ((ColumnName, ScalarType) -> ColumnName
forall a b. (a, b) -> a
fst ((ColumnName, ScalarType) -> ColumnName)
-> HashMap ColumnName (ColumnName, ScalarType)
-> HashMap ColumnName ColumnName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashMap ColumnName (ColumnName, ScalarType)
joinColumnMapping)
        SelectFromG 'BigQuery (UnpreparedValue 'BigQuery)
jsonToRecordSet
        (Text -> ColumnName
BigQuery.ColumnName (Text -> ColumnName) -> Text -> ColumnName
forall a b. (a -> b) -> a -> b
$ FieldName -> Text
getFieldNameTxt FieldName
argumentId)
        (ScalarType 'BigQuery -> ColumnType 'BigQuery
forall (b :: BackendType). ScalarType b -> ColumnType b
ColumnScalar ScalarType 'BigQuery
ScalarType
BigQuery.IntegerScalarType)
        (FieldName,
 SourceRelationshipSelection 'BigQuery Void UnpreparedValue)
relationship
        StringifyNumbers
stringifyNumbers