2022-01-06 12:49:03 +03:00
|
|
|
{-# OPTIONS_HADDOCK ignore-exports #-}
|
|
|
|
|
|
|
|
-- | Responsible for translating and building an MSSQL execution plan for
|
|
|
|
-- delete mutations.
|
|
|
|
--
|
|
|
|
-- This module is used by "Hasura.Backends.MSSQL.Instances.Execute".
|
|
|
|
module Hasura.Backends.MSSQL.Execute.Delete
|
|
|
|
( executeDelete,
|
|
|
|
)
|
|
|
|
where
|
|
|
|
|
|
|
|
import Database.MSSQL.Transaction qualified as Tx
|
|
|
|
import Hasura.Backends.MSSQL.Connection
|
2022-04-28 22:33:33 +03:00
|
|
|
import Hasura.Backends.MSSQL.Execute.QueryTags
|
2022-01-06 12:49:03 +03:00
|
|
|
import Hasura.Backends.MSSQL.FromIr as TSQL
|
2022-03-10 13:33:55 +03:00
|
|
|
import Hasura.Backends.MSSQL.FromIr.Constants (tempTableNameDeleted)
|
|
|
|
import Hasura.Backends.MSSQL.FromIr.Delete qualified as TSQL
|
|
|
|
import Hasura.Backends.MSSQL.FromIr.MutationResponse
|
|
|
|
import Hasura.Backends.MSSQL.FromIr.SelectIntoTempTable qualified as TSQL
|
2022-01-06 12:49:03 +03:00
|
|
|
import Hasura.Backends.MSSQL.Plan
|
2022-02-07 17:11:49 +03:00
|
|
|
import Hasura.Backends.MSSQL.SQL.Error
|
2022-01-06 12:49:03 +03:00
|
|
|
import Hasura.Backends.MSSQL.ToQuery as TQ
|
|
|
|
import Hasura.Backends.MSSQL.Types.Internal as TSQL
|
|
|
|
import Hasura.Base.Error
|
|
|
|
import Hasura.EncJSON
|
|
|
|
import Hasura.GraphQL.Parser
|
|
|
|
import Hasura.Prelude
|
2022-04-28 22:33:33 +03:00
|
|
|
import Hasura.QueryTags (QueryTagsComment)
|
2022-01-06 12:49:03 +03:00
|
|
|
import Hasura.RQL.IR
|
2022-04-27 16:57:28 +03:00
|
|
|
import Hasura.RQL.Types.Backend
|
|
|
|
import Hasura.RQL.Types.Common
|
|
|
|
import Hasura.SQL.Backend
|
2022-01-06 12:49:03 +03:00
|
|
|
import Hasura.Session
|
|
|
|
|
|
|
|
-- | Executes a Delete IR AST and return results as JSON.
|
|
|
|
executeDelete ::
|
2022-04-28 22:33:33 +03:00
|
|
|
(MonadError QErr m, MonadReader QueryTagsComment m) =>
|
2022-01-06 12:49:03 +03:00
|
|
|
UserInfo ->
|
2022-02-23 23:17:58 +03:00
|
|
|
StringifyNumbers ->
|
2022-01-06 12:49:03 +03:00
|
|
|
SourceConfig 'MSSQL ->
|
|
|
|
AnnDelG 'MSSQL Void (UnpreparedValue 'MSSQL) ->
|
|
|
|
m (ExceptT QErr IO EncJSON)
|
|
|
|
executeDelete userInfo stringifyNum sourceConfig deleteOperation = do
|
2022-04-28 22:33:33 +03:00
|
|
|
queryTags <- ask
|
2022-01-06 12:49:03 +03:00
|
|
|
preparedDelete <- traverse (prepareValueQuery $ _uiSession userInfo) deleteOperation
|
2022-04-28 22:33:33 +03:00
|
|
|
pure $ mssqlRunReadWrite (_mscExecCtx sourceConfig) (buildDeleteTx preparedDelete stringifyNum queryTags)
|
2022-01-06 12:49:03 +03:00
|
|
|
|
|
|
|
-- | Converts a Delete IR AST to a transaction of three delete sql statements.
|
|
|
|
--
|
|
|
|
-- A GraphQL delete mutation does two things:
|
|
|
|
--
|
|
|
|
-- 1. Deletes rows in a table according to some predicate
|
|
|
|
-- 2. (Potentially) returns the deleted rows (including relationships) as JSON
|
|
|
|
--
|
|
|
|
-- In order to complete these 2 things we need 3 SQL statements:
|
|
|
|
--
|
|
|
|
-- 1. @SELECT INTO <temp_table> WHERE <false>@ - creates a temporary table
|
|
|
|
-- with the same schema as the original table in which we'll store the deleted rows
|
|
|
|
-- from the table we are deleting
|
|
|
|
-- 2. @DELETE FROM with OUTPUT@ - deletes the rows from the table and inserts the
|
|
|
|
-- deleted rows to the temporary table from (1)
|
|
|
|
-- 3. @SELECT@ - constructs the @returning@ query from the temporary table, including
|
|
|
|
-- relationships with other tables.
|
|
|
|
buildDeleteTx ::
|
|
|
|
AnnDel 'MSSQL ->
|
2022-02-23 23:17:58 +03:00
|
|
|
StringifyNumbers ->
|
2022-04-28 22:33:33 +03:00
|
|
|
QueryTagsComment ->
|
2022-01-06 12:49:03 +03:00
|
|
|
Tx.TxET QErr IO EncJSON
|
2022-04-28 22:33:33 +03:00
|
|
|
buildDeleteTx deleteOperation stringifyNum queryTags = do
|
2022-01-06 12:49:03 +03:00
|
|
|
let withAlias = "with_alias"
|
|
|
|
createInsertedTempTableQuery =
|
|
|
|
toQueryFlat $
|
|
|
|
TQ.fromSelectIntoTempTable $
|
2022-03-10 09:17:48 +03:00
|
|
|
TSQL.toSelectIntoTempTable tempTableNameDeleted (_adTable deleteOperation) (_adAllCols deleteOperation) RemoveConstraints
|
2022-01-06 12:49:03 +03:00
|
|
|
-- Create a temp table
|
2022-04-28 22:33:33 +03:00
|
|
|
Tx.unitQueryE defaultMSSQLTxErrorHandler (createInsertedTempTableQuery `withQueryTags` queryTags)
|
2022-01-06 12:49:03 +03:00
|
|
|
let deleteQuery = TQ.fromDelete <$> TSQL.fromDelete deleteOperation
|
2022-03-10 13:33:55 +03:00
|
|
|
deleteQueryValidated <- toQueryFlat <$> runFromIr deleteQuery
|
2022-01-06 12:49:03 +03:00
|
|
|
-- Execute DELETE statement
|
2022-04-28 22:33:33 +03:00
|
|
|
Tx.unitQueryE mutationMSSQLTxErrorHandler (deleteQueryValidated `withQueryTags` queryTags)
|
2022-03-10 13:33:55 +03:00
|
|
|
mutationOutputSelect <- runFromIr $ mkMutationOutputSelect stringifyNum withAlias $ _adOutput deleteOperation
|
|
|
|
|
2022-01-06 12:49:03 +03:00
|
|
|
let withSelect =
|
|
|
|
emptySelect
|
|
|
|
{ selectProjections = [StarProjection],
|
|
|
|
selectFrom = Just $ FromTempTable $ Aliased tempTableNameDeleted "deleted_alias"
|
|
|
|
}
|
|
|
|
finalMutationOutputSelect = mutationOutputSelect {selectWith = Just $ With $ pure $ Aliased withSelect withAlias}
|
|
|
|
mutationOutputSelectQuery = toQueryFlat $ TQ.fromSelect finalMutationOutputSelect
|
|
|
|
-- Execute SELECT query and fetch mutation response
|
2022-05-26 18:20:43 +03:00
|
|
|
result <- encJFromText <$> Tx.singleRowQueryE defaultMSSQLTxErrorHandler (mutationOutputSelectQuery `withQueryTags` queryTags)
|
|
|
|
-- delete the temporary table
|
|
|
|
let dropDeletedTempTableQuery = toQueryFlat $ dropTempTableQuery tempTableNameDeleted
|
|
|
|
Tx.unitQueryE defaultMSSQLTxErrorHandler (dropDeletedTempTableQuery `withQueryTags` queryTags)
|
|
|
|
-- return results
|
|
|
|
pure result
|