2021-06-11 06:26:50 +03:00
|
|
|
{- |
|
|
|
|
Working example:
|
|
|
|
|
|
|
|
$ curl -XPOST http://localhost:8080/v2/query -d @- <<EOF
|
|
|
|
{
|
|
|
|
"type":"bigquery_run_sql",
|
|
|
|
"args": {
|
|
|
|
"sql":"select 3 * 4 as foo, \"Hello, World!\" as bar",
|
|
|
|
"source":"chinook"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EOF
|
|
|
|
{"result_type":"TuplesOk","result":[["foo","bar"],["12","Hello, World!"]]}
|
|
|
|
-}
|
2021-04-12 13:18:29 +03:00
|
|
|
|
|
|
|
module Hasura.Backends.BigQuery.DDL.RunSQL
|
|
|
|
( runSQL
|
|
|
|
, runDatabaseInspection
|
|
|
|
, BigQueryRunSQL
|
|
|
|
)
|
|
|
|
where
|
|
|
|
|
2021-04-22 00:44:37 +03:00
|
|
|
import Hasura.Prelude
|
|
|
|
|
2021-04-12 13:18:29 +03:00
|
|
|
import qualified Data.Aeson as J
|
|
|
|
import qualified Data.HashMap.Strict.InsOrd as OMap
|
|
|
|
import qualified Data.Text as T
|
|
|
|
import qualified Data.Text.Lazy as LT
|
|
|
|
import qualified Data.Vector as V
|
|
|
|
|
2021-04-22 00:44:37 +03:00
|
|
|
import Data.Aeson.TH (deriveJSON)
|
|
|
|
import Data.Aeson.Text (encodeToLazyText)
|
|
|
|
|
|
|
|
import qualified Hasura.Backends.BigQuery.DataLoader.Execute as Execute
|
2021-04-12 13:18:29 +03:00
|
|
|
import qualified Hasura.Backends.BigQuery.DataLoader.Plan as Plan
|
2021-04-22 00:44:37 +03:00
|
|
|
|
2021-04-12 13:18:29 +03:00
|
|
|
import Hasura.Backends.BigQuery.Source (BigQuerySourceConfig (..))
|
2021-05-11 18:18:31 +03:00
|
|
|
import Hasura.Base.Error
|
2021-04-12 13:18:29 +03:00
|
|
|
import Hasura.EncJSON
|
|
|
|
import Hasura.RQL.DDL.Schema (RunSQLRes (..))
|
2021-05-11 18:18:31 +03:00
|
|
|
import Hasura.RQL.Types (CacheRWM, MetadataM, SourceName,
|
|
|
|
askSourceConfig)
|
2021-04-22 00:44:37 +03:00
|
|
|
import Hasura.SQL.Backend
|
|
|
|
|
2021-04-12 13:18:29 +03:00
|
|
|
|
|
|
|
data BigQueryRunSQL
|
|
|
|
= BigQueryRunSQL
|
|
|
|
{ _mrsSql :: Text
|
|
|
|
, _mrsSource :: !SourceName
|
|
|
|
} deriving (Show, Eq)
|
|
|
|
$(deriveJSON hasuraJSON ''BigQueryRunSQL)
|
|
|
|
|
|
|
|
runSQL ::
|
|
|
|
(MonadIO m, CacheRWM m, MonadError QErr m, MetadataM m) =>
|
|
|
|
BigQueryRunSQL ->
|
|
|
|
m EncJSON
|
|
|
|
runSQL = runSQL_ recordSetAsHeaderAndRows
|
|
|
|
|
|
|
|
-- | The SQL query in the request is ignored
|
|
|
|
runDatabaseInspection ::
|
|
|
|
(MonadIO m, CacheRWM m, MonadError QErr m, MetadataM m) =>
|
|
|
|
BigQueryRunSQL ->
|
|
|
|
m EncJSON
|
|
|
|
runDatabaseInspection (BigQueryRunSQL _query source) = do
|
2021-04-22 00:44:37 +03:00
|
|
|
BigQuerySourceConfig{_scDatasets = dataSets} <- askSourceConfig @'BigQuery source
|
2021-04-12 13:18:29 +03:00
|
|
|
let queries = ["SELECT *, ARRAY(SELECT as STRUCT * from " <>
|
|
|
|
dataSet <> ".INFORMATION_SCHEMA.COLUMNS WHERE table_name = t.table_name) as columns from " <>
|
|
|
|
dataSet <> ".INFORMATION_SCHEMA.TABLES as t" | dataSet <- dataSets]
|
|
|
|
query' = T.intercalate " UNION ALL " queries
|
|
|
|
runSQL_ recordSetAsSchema (BigQueryRunSQL query' source)
|
|
|
|
|
|
|
|
runSQL_ ::
|
|
|
|
(MonadIO m, CacheRWM m, MonadError QErr m, MetadataM m) =>
|
2021-04-22 00:44:37 +03:00
|
|
|
(Execute.RecordSet -> J.Value) ->
|
2021-04-12 13:18:29 +03:00
|
|
|
BigQueryRunSQL ->
|
|
|
|
m EncJSON
|
|
|
|
runSQL_ f (BigQueryRunSQL query source) = do
|
2021-04-22 00:44:37 +03:00
|
|
|
sourceConfig <- askSourceConfig @'BigQuery source
|
2021-04-12 13:18:29 +03:00
|
|
|
result <-
|
2021-04-22 00:44:37 +03:00
|
|
|
Execute.streamBigQuery
|
2021-04-12 13:18:29 +03:00
|
|
|
sourceConfig
|
|
|
|
Execute.BigQuery {query = LT.fromStrict query, parameters = mempty}
|
|
|
|
case result of
|
2021-04-22 00:44:37 +03:00
|
|
|
Left queryError -> throw400 BigQueryError (tshow queryError) -- TODO: Pretty print the error type.
|
2021-04-12 13:18:29 +03:00
|
|
|
Right recordSet ->
|
|
|
|
pure
|
|
|
|
(encJFromJValue
|
|
|
|
(RunSQLRes "TuplesOk" (f recordSet)))
|
|
|
|
|
2021-04-22 00:44:37 +03:00
|
|
|
recordSetAsHeaderAndRows :: Execute.RecordSet -> J.Value
|
|
|
|
recordSetAsHeaderAndRows Execute.RecordSet {rows} = J.toJSON (thead : tbody)
|
2021-04-12 13:18:29 +03:00
|
|
|
where
|
|
|
|
thead =
|
|
|
|
case rows V.!? 0 of
|
|
|
|
Nothing -> []
|
|
|
|
Just row ->
|
|
|
|
map (J.toJSON . (coerce :: Plan.FieldName -> Text)) (OMap.keys row)
|
|
|
|
tbody :: [[J.Value]]
|
|
|
|
tbody = map (\row -> map J.toJSON (OMap.elems row)) (toList rows)
|
|
|
|
|
2021-04-22 00:44:37 +03:00
|
|
|
recordSetAsSchema :: Execute.RecordSet -> J.Value
|
|
|
|
recordSetAsSchema rs@(Execute.RecordSet {rows}) =
|
2021-04-12 13:18:29 +03:00
|
|
|
recordSetAsHeaderAndRows $
|
2021-04-22 00:44:37 +03:00
|
|
|
rs { Execute.rows = OMap.adjust
|
|
|
|
(Execute.TextOutputValue . LT.toStrict . encodeToLazyText . J.toJSON)
|
2021-04-12 13:18:29 +03:00
|
|
|
(Plan.FieldName "columns") <$> rows }
|