mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-18 13:02:11 +03:00
63eabc2374
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8469 Co-authored-by: Daniel Chambers <1214352+daniel-chambers@users.noreply.github.com> GitOrigin-RevId: 6f2aebc150d7c93490e6da3ada5c282dd3d9a56c
116 lines
4.9 KiB
Haskell
116 lines
4.9 KiB
Haskell
module Test.DataExport
|
|
( exportData,
|
|
)
|
|
where
|
|
|
|
import Command (ExportDataConfig (..), ExportFormat (..))
|
|
import Control.Lens ((&))
|
|
import Data.Aeson qualified as J
|
|
import Data.Aeson.Encoding qualified as JE
|
|
import Data.ByteString.Lazy qualified as BSL
|
|
import Data.HashMap.Strict (HashMap)
|
|
import Data.HashMap.Strict qualified as HashMap
|
|
import Data.List.NonEmpty qualified as NonEmpty
|
|
import Data.Maybe (fromMaybe)
|
|
import Data.Text (Text)
|
|
import Data.Text qualified as Text
|
|
import Data.Time (ZonedTime, defaultTimeLocale)
|
|
import Data.Time.Format (formatTime)
|
|
import Data.Time.Format.ISO8601 (iso8601ParseM)
|
|
import Hasura.Backends.DataConnector.API
|
|
import System.Directory qualified as Directory
|
|
import System.FilePath ((<.>), (</>))
|
|
import Test.Data qualified as Data
|
|
import Prelude
|
|
|
|
exportData :: ExportDataConfig -> IO ()
|
|
exportData exportDataConfig@ExportDataConfig {..} = do
|
|
absDirectory <- Directory.makeAbsolute _edcDirectory
|
|
Directory.createDirectoryIfMissing True absDirectory
|
|
putStrLn $ "Exporting to " <> absDirectory
|
|
case _edcFormat of
|
|
JSON -> exportTablePerFile exportDataConfig absDirectory (convertTable ".json" convertTableToJSON)
|
|
JSONLines -> exportTablePerFile exportDataConfig absDirectory (convertTable ".json" convertTableToJSONLines)
|
|
SingleJSONFile -> exportSingleJSONFile exportDataConfig absDirectory
|
|
|
|
exportTablePerFile :: ExportDataConfig -> FilePath -> (TableName -> [HashMap FieldName FieldValue] -> (FilePath, BSL.ByteString)) -> IO ()
|
|
exportTablePerFile ExportDataConfig {..} directory convertTable' = do
|
|
Data.schemaTables
|
|
& fmap (\tableInfo@TableInfo {..} -> (tableInfo,) <$> fromMaybe [] $ HashMap.lookup _tiName Data.allTableRows)
|
|
& mapM_ \(tableInfo@TableInfo {..}, rows) -> do
|
|
let rows' = maybe rows (\formatString -> formatDateColumnsInRow formatString tableInfo <$> rows) _edcDateTimeFormat
|
|
let (filename, contents) = convertTable' _tiName rows'
|
|
let destFile = directory </> filename
|
|
BSL.writeFile destFile contents
|
|
putStrLn $ "Exported " <> filename
|
|
|
|
convertTable :: String -> ([HashMap FieldName FieldValue] -> BSL.ByteString) -> TableName -> [HashMap FieldName FieldValue] -> (FilePath, BSL.ByteString)
|
|
convertTable extension convertRows tableName rows =
|
|
(filename, fileContents)
|
|
where
|
|
filename = (Text.unpack . NonEmpty.last $ unTableName tableName) <.> extension
|
|
fileContents = convertRows rows
|
|
|
|
convertTableToJSON :: [HashMap FieldName FieldValue] -> BSL.ByteString
|
|
convertTableToJSON rows =
|
|
J.encode $ rows
|
|
|
|
convertTableToJSONLines :: [HashMap FieldName FieldValue] -> BSL.ByteString
|
|
convertTableToJSONLines rows =
|
|
BSL.intercalate "\n" $ J.encode <$> rows
|
|
|
|
formatDateColumnsInRow :: String -> TableInfo -> HashMap FieldName FieldValue -> HashMap FieldName FieldValue
|
|
formatDateColumnsInRow dateTimeFormatString TableInfo {..} row =
|
|
row
|
|
& HashMap.mapWithKey
|
|
( \fieldName fieldValue ->
|
|
if fieldName `elem` dateFields
|
|
then fromMaybe fieldValue $ tryFormatDate fieldValue
|
|
else fieldValue
|
|
)
|
|
where
|
|
dateFields = fmap (\ColumnInfo {..} -> FieldName $ unColumnName _ciName) $ filter (\ColumnInfo {..} -> _ciType == dateTimeScalarType) _tiColumns
|
|
dateTimeScalarType = ScalarType "DateTime"
|
|
tryFormatDate fieldValue = case deserializeAsColumnFieldValue fieldValue of
|
|
J.String value -> do
|
|
(zonedTime :: ZonedTime) <- iso8601ParseM $ Text.unpack value
|
|
let formattedString = formatTime defaultTimeLocale dateTimeFormatString zonedTime
|
|
Just . mkColumnFieldValue . J.String . Text.pack $ formattedString
|
|
_ -> Nothing
|
|
|
|
exportSingleJSONFile :: ExportDataConfig -> FilePath -> IO ()
|
|
exportSingleJSONFile exportDataConfig directory = do
|
|
let filename = "Chinook.json"
|
|
let destFile = directory </> filename
|
|
BSL.writeFile destFile $ encodeSingleJSONFile exportDataConfig
|
|
putStrLn $ "Exported " <> filename
|
|
|
|
encodeSingleJSONFile :: ExportDataConfig -> BSL.ByteString
|
|
encodeSingleJSONFile ExportDataConfig {..} =
|
|
JE.encodingToLazyByteString $
|
|
JE.list
|
|
( \tableInfo@TableInfo {..} ->
|
|
let rows = fromMaybe [] $ HashMap.lookup _tiName Data.allTableRows
|
|
rows' = maybe rows (\formatString -> formatDateColumnsInRow formatString tableInfo <$> rows) _edcDateTimeFormat
|
|
in encodeSingleJSONFileTable tableInfo rows'
|
|
)
|
|
Data.schemaTables
|
|
|
|
encodeSingleJSONFileTable :: TableInfo -> [HashMap FieldName FieldValue] -> J.Encoding
|
|
encodeSingleJSONFileTable TableInfo {..} rows =
|
|
encodeAssocListAsObject
|
|
[ ("tableName", J.toEncoding . NonEmpty.last $ unTableName _tiName),
|
|
("columns", encodeAssocListAsObject columns),
|
|
("rows", J.toEncoding rows)
|
|
]
|
|
where
|
|
columns :: [(Text, J.Encoding)]
|
|
columns = (\ColumnInfo {..} -> (unColumnName _ciName, J.toEncoding _ciType)) <$> _tiColumns
|
|
|
|
encodeAssocListAsObject :: [(Text, J.Encoding)] -> J.Encoding
|
|
encodeAssocListAsObject =
|
|
JE.dict
|
|
JE.text
|
|
id
|
|
(\fn -> foldr (uncurry fn))
|