module IHP.IDE.Data.View.ShowQuery where import qualified Database.PostgreSQL.Simple as PG import IHP.ViewPrelude import IHP.IDE.ToolServer.Types import IHP.IDE.Data.View.Layout data ShowQueryView = ShowQueryView { ShowQueryView -> Maybe (Either SqlError SqlConsoleResult) queryResult :: Maybe (Either PG.SqlError SqlConsoleResult) , ShowQueryView -> Text queryText :: Text } instance View ShowQueryView where html :: ShowQueryView -> Html html ShowQueryView { Maybe (Either SqlError SqlConsoleResult) Text queryText :: Text queryResult :: Maybe (Either SqlError SqlConsoleResult) $sel:queryText:ShowQueryView :: ShowQueryView -> Text $sel:queryResult:ShowQueryView :: ShowQueryView -> Maybe (Either SqlError SqlConsoleResult) .. } = [hsx| <div class="h-100"> {headerNav} <div class="container-fluid mt-2"> <form method="GET" action={QueryAction} class="sql-repl"> <input type="hidden" name="query" value={queryText}/> <div class="p-2 rounded my-2" style="background-color: #002B36; border: 1px solid #0B5163;"> <div class="query-editor" style="height:16px">{queryText}</div> </div> <button class="btn btn-primary" data-toggle="tooltip" data-placement="right" title="⌘ Enter" >Run SQL Query</button> </form> <div class="mt-3"> {renderRows} </div> </div> </div> |] where renderRows :: Html renderRows = case Maybe (Either SqlError SqlConsoleResult) queryResult of Just ((Right (SelectQueryResult []))) -> [hsx| <div class="text-muted"> The query returned an empty result set. </div> |] Just (Right (SelectQueryResult [[DynamicField]] rows)) -> [hsx| <table class="table table-sm table-hover table-striped data-rows-table"> {tableHead rows} {tableBody rows} </table> |] Just (Right (InsertOrUpdateResult Int64 count)) -> [hsx| <div class="text-muted"> {count} {if count == 1 then "row" :: Text else "rows"} affected. </div> |] Just (Left SqlError sqlError) -> [hsx| <div class="alert alert-danger" role="alert"> <h4 class="alert-heading">SQL Error - {get #sqlExecStatus sqlError}</h4> {showIfNotEmpty "Message" (get #sqlErrorMsg sqlError)} {showIfNotEmpty "Details" (get #sqlErrorDetail sqlError)} {showIfNotEmpty "Hint" (get #sqlErrorHint sqlError)} {showIfNotEmpty "State" (get #sqlState sqlError)} </div> |] Maybe (Either SqlError SqlConsoleResult) Nothing -> Html forall a. Monoid a => a mempty tableHead :: [[model]] -> Html tableHead [[model]] rows = [hsx|<thead><tr>{forEach (columnNames rows) renderColumnHead}</tr></thead>|] renderColumnHead :: a -> Html renderColumnHead a name = [hsx|<th>{name}</th>|] tableBody :: mono -> Html tableBody mono rows = [hsx|<tbody>{forEach rows renderRow}</tbody>|] renderRow :: mono -> Html renderRow mono fields = [hsx|<tr>{forEach fields renderField}</tr>|] renderField :: DynamicField -> Html renderField DynamicField { Maybe ByteString ByteString $sel:fieldName:DynamicField :: DynamicField -> ByteString $sel:fieldValue:DynamicField :: DynamicField -> Maybe ByteString fieldName :: ByteString fieldValue :: Maybe ByteString .. } = [hsx|<td><span data-fieldname={fieldName}>{sqlValueToText fieldValue}</span></td>|] columnNames :: [[model]] -> [a] columnNames [[model]] rows = [a] -> ([model] -> [a]) -> Maybe [model] -> [a] forall b a. b -> (a -> b) -> Maybe a -> b maybe [] ((model -> a) -> [model] -> [a] forall a b. (a -> b) -> [a] -> [b] map (Proxy "fieldName" -> model -> a forall model (name :: Symbol) value. (KnownSymbol name, HasField name model value) => Proxy name -> model -> value get IsLabel "fieldName" (Proxy "fieldName") Proxy "fieldName" #fieldName)) ([[model]] -> Maybe [model] forall a. [a] -> Maybe a head [[model]] rows) showIfNotEmpty :: Text -> ByteString -> Html showIfNotEmpty :: Text -> ByteString -> Html showIfNotEmpty Text title = \case ByteString "" -> Html forall a. Monoid a => a mempty ByteString text -> [hsx|<div><strong>{title}:</strong> {text}</div>|]