mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 01:12:56 +03:00
Add tests for delete mutations to the Data Connector agent test suite
[GDC-721]: https://hasurahq.atlassian.net/browse/GDC-721?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8067 GitOrigin-RevId: bf5b7e7c20c6011d438888be6017331def7063bf
This commit is contained in:
parent
d2832f1067
commit
190e429eef
@ -127,7 +127,7 @@ cabal run dc-api:test:tests-dc-api -- test --agent-base-url http://localhost:810
|
||||
From the HGE repo.
|
||||
|
||||
## Known Issues
|
||||
* Using "returning" in update mutations where you join across relationships that are affected by the update mutation itself may return inconsistent results. This is because of this issue with SQLite: https://sqlite.org/forum/forumpost/9470611066
|
||||
* Using "returning" in update/delete mutations where you join across relationships that are affected by the update/delete mutation itself may return inconsistent results. This is because of this issue with SQLite: https://sqlite.org/forum/forumpost/9470611066
|
||||
|
||||
## TODO
|
||||
|
||||
|
@ -161,6 +161,7 @@ test-suite tests-dc-api
|
||||
Test.Specs.HealthSpec
|
||||
Test.Specs.MetricsSpec
|
||||
Test.Specs.MutationSpec
|
||||
Test.Specs.MutationSpec.DeleteSpec
|
||||
Test.Specs.MutationSpec.InsertSpec
|
||||
Test.Specs.MutationSpec.UpdateSpec
|
||||
Test.Specs.QuerySpec
|
||||
|
@ -39,6 +39,9 @@ module Hasura.Backends.DataConnector.API.V0.Mutations
|
||||
RowUpdate (..),
|
||||
RowColumnOperatorValue (..),
|
||||
DeleteMutationOperation (..),
|
||||
dmoTable,
|
||||
dmoWhere,
|
||||
dmoReturningFields,
|
||||
MutationResponse (..),
|
||||
mrOperationResults,
|
||||
MutationOperationResults (..),
|
||||
@ -512,5 +515,6 @@ instance HasCodec MutationOperationResults where
|
||||
$(makeLenses ''MutationRequest)
|
||||
$(makeLenses ''InsertMutationOperation)
|
||||
$(makeLenses ''UpdateMutationOperation)
|
||||
$(makeLenses ''DeleteMutationOperation)
|
||||
$(makeLenses ''MutationResponse)
|
||||
$(makeLenses ''MutationOperationResults)
|
||||
|
@ -276,13 +276,15 @@ tracksTableRelationships =
|
||||
mediaTypeJoinFieldMapping = HashMap.fromList [(API.ColumnName "MediaTypeId", API.ColumnName "MediaTypeId")]
|
||||
albumJoinFieldMapping = HashMap.fromList [(API.ColumnName "AlbumId", API.ColumnName "AlbumId")]
|
||||
genreJoinFieldMapping = HashMap.fromList [(API.ColumnName "GenreId", API.ColumnName "GenreId")]
|
||||
playlistTracksJoinFieldMapping = HashMap.fromList [(API.ColumnName "TrackId", API.ColumnName "TrackId")]
|
||||
in API.TableRelationships
|
||||
tracksTableName
|
||||
( HashMap.fromList
|
||||
[ (invoiceLinesRelationshipName, API.Relationship invoiceLinesTableName API.ArrayRelationship invoiceLinesJoinFieldMapping),
|
||||
(mediaTypeRelationshipName, API.Relationship mediaTypesTableName API.ObjectRelationship mediaTypeJoinFieldMapping),
|
||||
(albumRelationshipName, API.Relationship albumsTableName API.ObjectRelationship albumJoinFieldMapping),
|
||||
(genreRelationshipName, API.Relationship genresTableName API.ObjectRelationship genreJoinFieldMapping)
|
||||
(genreRelationshipName, API.Relationship genresTableName API.ObjectRelationship genreJoinFieldMapping),
|
||||
(playlistTracksRelationshipName, API.Relationship playlistTracksTableName API.ArrayRelationship playlistTracksJoinFieldMapping)
|
||||
]
|
||||
)
|
||||
|
||||
@ -298,6 +300,9 @@ albumRelationshipName = API.RelationshipName "Album"
|
||||
genreRelationshipName :: API.RelationshipName
|
||||
genreRelationshipName = API.RelationshipName "Genre"
|
||||
|
||||
playlistTracksRelationshipName :: API.RelationshipName
|
||||
playlistTracksRelationshipName = API.RelationshipName "PlaylistTracks"
|
||||
|
||||
genresTableName :: API.TableName
|
||||
genresTableName = mkTableName "Genre"
|
||||
|
||||
@ -393,6 +398,10 @@ data TestData = TestData
|
||||
_tdMediaTypeRelationshipName :: API.RelationshipName,
|
||||
_tdAlbumRelationshipName :: API.RelationshipName,
|
||||
_tdGenreRelationshipName :: API.RelationshipName,
|
||||
_tdPlaylistTracksRelationshipName :: API.RelationshipName,
|
||||
-- = PlaylistTracks table
|
||||
_tdPlaylistTracksTableName :: API.TableName,
|
||||
_tdPlaylistTracksRows :: [HashMap API.FieldName API.FieldValue],
|
||||
-- = Genres table
|
||||
_tdGenresTableName :: API.TableName,
|
||||
_tdGenresRows :: [HashMap API.FieldName API.FieldValue],
|
||||
@ -454,6 +463,9 @@ mkTestData schemaResponse testConfig =
|
||||
_tdMediaTypeRelationshipName = mediaTypeRelationshipName,
|
||||
_tdAlbumRelationshipName = albumRelationshipName,
|
||||
_tdGenreRelationshipName = genreRelationshipName,
|
||||
_tdPlaylistTracksRelationshipName = playlistTracksRelationshipName,
|
||||
_tdPlaylistTracksTableName = formatTableName testConfig playlistTracksTableName,
|
||||
_tdPlaylistTracksRows = playlistTracksRows,
|
||||
_tdGenresTableName = formatTableName testConfig genresTableName,
|
||||
_tdGenresRows = genresRows,
|
||||
_tdGenresTableRelationships = formatTableRelationships genresTableRelationships,
|
||||
|
@ -7,6 +7,7 @@ import Data.Foldable (for_)
|
||||
import Hasura.Backends.DataConnector.API
|
||||
import Test.Data (EdgeCasesTestData, TestData)
|
||||
import Test.Sandwich (describe)
|
||||
import Test.Specs.MutationSpec.DeleteSpec qualified as DeleteSpec
|
||||
import Test.Specs.MutationSpec.InsertSpec qualified as InsertSpec
|
||||
import Test.Specs.MutationSpec.UpdateSpec qualified as UpdateSpec
|
||||
import Test.TestHelpers (AgentTestSpec)
|
||||
@ -18,3 +19,4 @@ spec testData edgeCasesTestData capabilities@Capabilities {..} = do
|
||||
for_ (_cMutations >>= _mcInsertCapabilities) $ \_insertCapabilities -> do
|
||||
InsertSpec.spec testData edgeCasesTestData capabilities
|
||||
UpdateSpec.spec testData edgeCasesTestData capabilities
|
||||
DeleteSpec.spec testData edgeCasesTestData capabilities
|
||||
|
385
server/lib/dc-api/test/Test/Specs/MutationSpec/DeleteSpec.hs
Normal file
385
server/lib/dc-api/test/Test/Specs/MutationSpec/DeleteSpec.hs
Normal file
@ -0,0 +1,385 @@
|
||||
module Test.Specs.MutationSpec.DeleteSpec (spec) where
|
||||
|
||||
import Control.Lens (ix, (&), (.~), (?~), (^?))
|
||||
import Control.Monad (when)
|
||||
import Data.Aeson qualified as J
|
||||
import Data.Functor ((<&>))
|
||||
import Data.HashMap.Strict (HashMap)
|
||||
import Data.List.NonEmpty (NonEmpty (..))
|
||||
import Data.Maybe (fromMaybe, maybeToList)
|
||||
import Hasura.Backends.DataConnector.API
|
||||
import Test.AgentAPI (mutationGuarded, queryGuarded)
|
||||
import Test.AgentDatasets (chinookTemplate, usesDataset)
|
||||
import Test.Data (EdgeCasesTestData (..), TestData (..))
|
||||
import Test.Data qualified as Data
|
||||
import Test.Expectations (mutationResponseShouldBe, rowsShouldBe)
|
||||
import Test.Sandwich (describe)
|
||||
import Test.TestHelpers (AgentTestSpec, it)
|
||||
import Test.TestHelpers qualified as Test
|
||||
import Prelude
|
||||
|
||||
spec :: TestData -> Maybe EdgeCasesTestData -> Capabilities -> AgentTestSpec
|
||||
spec TestData {..} edgeCasesTestData Capabilities {..} = describe "Delete Mutations" $ do
|
||||
usesDataset chinookTemplate $ it "can delete all rows" $ do
|
||||
let deleteOperation = mkDeleteOperation _tdInvoiceLinesTableName
|
||||
let mutationRequest = Data.emptyMutationRequest & mrOperations .~ [DeleteOperation deleteOperation]
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let expectedResult = MutationOperationResults 2240 Nothing
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
receivedInvoiceLines <- Data.sortResponseRowsBy "InvoiceLineId" <$> queryGuarded invoiceLinesQueryRequest
|
||||
Data.responseRows receivedInvoiceLines `rowsShouldBe` []
|
||||
|
||||
usesDataset chinookTemplate $ it "can delete a specific row" $ do
|
||||
let whereExp = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "InvoiceLineId" invoiceLineIdScalarType) (ScalarValue (J.Number 420) invoiceLineIdScalarType)
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
let mutationRequest = Data.emptyMutationRequest & mrOperations .~ [DeleteOperation deleteOperation]
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let expectedResult = MutationOperationResults 1 Nothing
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
let expectedRemainingRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter (\invoiceLine -> invoiceLine ^? Data.field "InvoiceLineId" . Data._ColumnFieldNumber /= Just 420)
|
||||
|
||||
receivedInvoiceLines <- Data.sortResponseRowsBy "InvoiceLineId" <$> queryGuarded invoiceLinesQueryRequest
|
||||
Data.responseRows receivedInvoiceLines `rowsShouldBe` expectedRemainingRows
|
||||
|
||||
usesDataset chinookTemplate $ it "can delete a range of rows" $ do
|
||||
let whereExp =
|
||||
And
|
||||
[ ApplyBinaryComparisonOperator GreaterThan (_tdCurrentComparisonColumn "InvoiceLineId" invoiceLineIdScalarType) (ScalarValue (J.Number 10) invoiceLineIdScalarType),
|
||||
ApplyBinaryComparisonOperator LessThanOrEqual (_tdCurrentComparisonColumn "InvoiceLineId" invoiceLineIdScalarType) (ScalarValue (J.Number 20) invoiceLineIdScalarType)
|
||||
]
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
let mutationRequest = Data.emptyMutationRequest & mrOperations .~ [DeleteOperation deleteOperation]
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let expectedResult = MutationOperationResults 10 Nothing
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
let expectedRemainingRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter
|
||||
( \invoiceLine ->
|
||||
invoiceLine ^? Data.field "InvoiceLineId" . Data._ColumnFieldNumber <= Just 10
|
||||
|| invoiceLine ^? Data.field "InvoiceLineId" . Data._ColumnFieldNumber > Just 20
|
||||
)
|
||||
|
||||
receivedInvoiceLines <- Data.sortResponseRowsBy "InvoiceLineId" <$> queryGuarded invoiceLinesQueryRequest
|
||||
Data.responseRows receivedInvoiceLines `rowsShouldBe` expectedRemainingRows
|
||||
|
||||
usesDataset chinookTemplate $ it "can perform multiple delete operations" $ do
|
||||
let whereExp1 = ApplyBinaryComparisonOperator LessThan (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (ScalarValue (J.Number 3) invoiceIdScalarType)
|
||||
let whereExp2 = ApplyBinaryComparisonOperator GreaterThan (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (ScalarValue (J.Number 410) invoiceIdScalarType)
|
||||
let deleteOperation1 =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp1
|
||||
let deleteOperation2 =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp2
|
||||
let mutationRequest = Data.emptyMutationRequest & mrOperations .~ [DeleteOperation deleteOperation1, DeleteOperation deleteOperation2]
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let expectedResult1 = MutationOperationResults 6 Nothing
|
||||
let expectedResult2 = MutationOperationResults 15 Nothing
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult1, expectedResult2]
|
||||
|
||||
let expectedRemainingRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter
|
||||
( \invoiceLine ->
|
||||
invoiceLine ^? Data.field "InvoiceId" . Data._ColumnFieldNumber >= Just 3
|
||||
&& invoiceLine ^? Data.field "InvoiceId" . Data._ColumnFieldNumber <= Just 410
|
||||
)
|
||||
|
||||
receivedInvoiceLines <- Data.sortResponseRowsBy "InvoiceLineId" <$> queryGuarded invoiceLinesQueryRequest
|
||||
Data.responseRows receivedInvoiceLines `rowsShouldBe` expectedRemainingRows
|
||||
|
||||
when ((_cComparisons >>= _ccSubqueryComparisonCapabilities <&> _ctccSupportsRelations) == Just True) $ do
|
||||
usesDataset chinookTemplate $ it "can delete rows filtered by a related table" $ do
|
||||
let whereExp =
|
||||
Exists (RelatedTable _tdTrackRelationshipName) $
|
||||
ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "Composer" composerScalarType) (ScalarValue (J.String "Eric Clapton") composerScalarType)
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
let tableRelationships = [Data.onlyKeepRelationships [_tdTrackRelationshipName] _tdInvoiceLinesTableRelationships]
|
||||
let mutationRequest =
|
||||
Data.emptyMutationRequest
|
||||
& mrOperations .~ [DeleteOperation deleteOperation]
|
||||
& mrTableRelationships .~ tableRelationships
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let expectedResult = MutationOperationResults 3 Nothing
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
let expectedRemainingRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter
|
||||
( \invoiceLine -> fromMaybe True $ do
|
||||
trackId <- invoiceLine ^? Data.field "TrackId" . Data._ColumnFieldNumber
|
||||
track <- _tdTracksRowsById ^? ix trackId
|
||||
pure $ track ^? Data.field "Composer" . Data._ColumnFieldString /= Just "Eric Clapton"
|
||||
)
|
||||
|
||||
receivedInvoiceLines <- Data.sortResponseRowsBy "InvoiceLineId" <$> queryGuarded (invoiceLinesQueryRequest & qrTableRelationships .~ tableRelationships)
|
||||
Data.responseRows receivedInvoiceLines `rowsShouldBe` expectedRemainingRows
|
||||
|
||||
describe "returning" $ do
|
||||
usesDataset chinookTemplate $ it "returns deleted rows" $ do
|
||||
let whereExp = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (ScalarValue (J.Number 10) invoiceIdScalarType)
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
& dmoReturningFields .~ invoiceLinesFields
|
||||
let mutationRequest = Data.emptyMutationRequest & mrOperations .~ [DeleteOperation deleteOperation]
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let expectedDeletedRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter (\invoiceLine -> invoiceLine ^? Data.field "InvoiceId" . Data._ColumnFieldNumber == Just 10)
|
||||
|
||||
let expectedResult = MutationOperationResults 6 (Just expectedDeletedRows)
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
usesDataset chinookTemplate $ it "can return deleted rows joined to additional rows from an object relationship" $ do
|
||||
let whereExp = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "InvoiceId" invoiceIdScalarType) (ScalarValue (J.Number 37) invoiceIdScalarType)
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
& dmoReturningFields
|
||||
.~ invoiceLinesFields
|
||||
<> Data.mkFieldsMap
|
||||
[ ( "Track",
|
||||
( RelField
|
||||
( RelationshipField _tdTrackRelationshipName $
|
||||
Data.emptyQuery
|
||||
& qFields
|
||||
?~ Data.mkFieldsMap
|
||||
[ ("TrackId", _tdColumnField _tdTracksTableName "TrackId"),
|
||||
("Name", _tdColumnField _tdTracksTableName "Name")
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
let tableRelationships = [Data.onlyKeepRelationships [_tdTrackRelationshipName] _tdInvoiceLinesTableRelationships]
|
||||
let mutationRequest =
|
||||
Data.emptyMutationRequest
|
||||
& mrOperations .~ [DeleteOperation deleteOperation]
|
||||
& mrTableRelationships .~ tableRelationships
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let joinInTrack (invoiceLine :: HashMap FieldName FieldValue) =
|
||||
let track = (invoiceLine ^? Data.field "TrackId" . Data._ColumnFieldNumber) >>= \trackId -> _tdTracksRowsById ^? ix trackId
|
||||
trackTrimmed = Data.filterColumns ["TrackId", "Name"] $ maybeToList track
|
||||
in Data.insertField "Track" (mkSubqueryResponse trackTrimmed) invoiceLine
|
||||
|
||||
let expectedDeletedRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter (\invoiceLine -> invoiceLine ^? Data.field "InvoiceId" . Data._ColumnFieldNumber == Just 37)
|
||||
& fmap joinInTrack
|
||||
|
||||
let expectedResult = MutationOperationResults 4 (Just expectedDeletedRows)
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
usesDataset chinookTemplate $ it "can return deleted rows joined to additional rows from an array relationship" $ do
|
||||
let whereExp = ApplyBinaryComparisonOperator Equal (_tdCurrentComparisonColumn "InvoiceLineId" invoiceLineIdScalarType) (ScalarValue (J.Number 2) invoiceLineIdScalarType)
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
& dmoReturningFields
|
||||
.~ invoiceLinesFields
|
||||
<> Data.mkFieldsMap
|
||||
[ ( "Track",
|
||||
( RelField
|
||||
( RelationshipField _tdTrackRelationshipName $
|
||||
Data.emptyQuery
|
||||
& qFields
|
||||
?~ Data.mkFieldsMap
|
||||
[ ("TrackId", _tdColumnField _tdTracksTableName "TrackId"),
|
||||
("Name", _tdColumnField _tdTracksTableName "Name"),
|
||||
( "PlaylistTracks",
|
||||
( RelField
|
||||
( RelationshipField _tdPlaylistTracksRelationshipName $
|
||||
Data.emptyQuery
|
||||
& qFields
|
||||
?~ Data.mkFieldsMap
|
||||
[ ("PlaylistId", _tdColumnField _tdPlaylistTracksTableName "PlaylistId"),
|
||||
("TrackId", _tdColumnField _tdPlaylistTracksTableName "TrackId")
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
let tableRelationships =
|
||||
[ Data.onlyKeepRelationships [_tdTrackRelationshipName] _tdInvoiceLinesTableRelationships,
|
||||
Data.onlyKeepRelationships [_tdPlaylistTracksRelationshipName] _tdTracksTableRelationships
|
||||
]
|
||||
let mutationRequest =
|
||||
Data.emptyMutationRequest
|
||||
& mrOperations .~ [DeleteOperation deleteOperation]
|
||||
& mrTableRelationships .~ tableRelationships
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let joinInPlaylistTracks (track :: HashMap FieldName FieldValue) =
|
||||
let trackId = track ^? Data.field "TrackId" . Data._ColumnFieldNumber
|
||||
playlistTracks = _tdPlaylistTracksRows & filter (\playlistTrack -> playlistTrack ^? Data.field "TrackId" . Data._ColumnFieldNumber == trackId)
|
||||
in Data.insertField "PlaylistTracks" (mkSubqueryResponse playlistTracks) track
|
||||
|
||||
let joinInTrack (invoiceLine :: HashMap FieldName FieldValue) =
|
||||
let track = (invoiceLine ^? Data.field "TrackId" . Data._ColumnFieldNumber) >>= \trackId -> _tdTracksRowsById ^? ix trackId
|
||||
trackTrimmed = Data.filterColumns ["TrackId", "Name"] $ maybeToList track
|
||||
in Data.insertField "Track" (mkSubqueryResponse (joinInPlaylistTracks <$> trackTrimmed)) invoiceLine
|
||||
|
||||
let expectedDeletedRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter (\invoiceLine -> invoiceLine ^? Data.field "InvoiceLineId" . Data._ColumnFieldNumber == Just 2)
|
||||
& fmap joinInTrack
|
||||
|
||||
let expectedResult = MutationOperationResults 1 (Just expectedDeletedRows)
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
usesDataset chinookTemplate $ it "deleted rows are not returned when returning them again across a relationship" $ do
|
||||
-- In this scenario we delete two invoice lines off an invoice, then we
|
||||
-- return those deleted lines, joining to their invoice and then back again
|
||||
-- to the invoice's lines, which should _not_ contain the two lines that were deleted
|
||||
let whereExp = ApplyBinaryArrayComparisonOperator In (_tdCurrentComparisonColumn "InvoiceLineId" invoiceLineIdScalarType) [J.Number 4, J.Number 5] invoiceLineIdScalarType
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _tdInvoiceLinesTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
& dmoReturningFields
|
||||
.~ invoiceLinesFields
|
||||
<> Data.mkFieldsMap
|
||||
[ ( "Invoice",
|
||||
( RelField
|
||||
( RelationshipField _tdInvoiceRelationshipName $
|
||||
Data.emptyQuery
|
||||
& qFields
|
||||
?~ Data.mkFieldsMap
|
||||
[ ("InvoiceId", _tdColumnField _tdInvoicesTableName "InvoiceId"),
|
||||
("Total", _tdColumnField _tdInvoicesTableName "Total"),
|
||||
( "InvoiceLines",
|
||||
( RelField
|
||||
( RelationshipField _tdInvoiceLinesRelationshipName $
|
||||
Data.emptyQuery
|
||||
& qFields ?~ invoiceLinesFields
|
||||
& qOrderBy ?~ OrderBy mempty (_tdOrderByColumn [] "InvoiceLineId" Ascending :| [])
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
let tableRelationships =
|
||||
[ Data.onlyKeepRelationships [_tdInvoiceRelationshipName] _tdInvoiceLinesTableRelationships,
|
||||
Data.onlyKeepRelationships [_tdInvoiceLinesRelationshipName] _tdInvoicesTableRelationships
|
||||
]
|
||||
let mutationRequest =
|
||||
Data.emptyMutationRequest
|
||||
& mrOperations .~ [DeleteOperation deleteOperation]
|
||||
& mrTableRelationships .~ tableRelationships
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let remainingInvoiceLines =
|
||||
_tdInvoiceLinesRows & filter (\invoiceLine -> invoiceLine ^? Data.field "InvoiceLineId" . Data._ColumnFieldNumber `notElem` [Just 4, Just 5])
|
||||
|
||||
let joinInInvoiceLines (invoice :: HashMap FieldName FieldValue) =
|
||||
let invoiceId = invoice ^? Data.field "InvoiceId" . Data._ColumnFieldNumber
|
||||
invoiceLines = remainingInvoiceLines & filter (\invoiceLine -> invoiceLine ^? Data.field "InvoiceId" . Data._ColumnFieldNumber == invoiceId)
|
||||
in Data.insertField "InvoiceLines" (mkSubqueryResponse invoiceLines) invoice
|
||||
|
||||
let joinInInvoice (invoiceLine :: HashMap FieldName FieldValue) =
|
||||
let invoice = (invoiceLine ^? Data.field "InvoiceId" . Data._ColumnFieldNumber) >>= \invoiceId -> _tdInvoicesRowsById ^? ix invoiceId
|
||||
invoiceTrimmed = Data.filterColumns ["InvoiceId", "Total"] $ maybeToList invoice
|
||||
in Data.insertField "Invoice" (mkSubqueryResponse (joinInInvoiceLines <$> invoiceTrimmed)) invoiceLine
|
||||
|
||||
let expectedDeletedRows =
|
||||
_tdInvoiceLinesRows
|
||||
& filter (\invoiceLine -> invoiceLine ^? Data.field "InvoiceLineId" . Data._ColumnFieldNumber `elem` [Just 4, Just 5])
|
||||
& fmap joinInInvoice
|
||||
|
||||
let expectedResult = MutationOperationResults 2 (Just expectedDeletedRows)
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
|
||||
describe "edge cases" $
|
||||
edgeCaseTest _ectdNoPrimaryKeyTableName "can delete rows in a table with no primary key" $ \EdgeCasesTestData {..} -> do
|
||||
let firstNameScalarType = _ectdFindColumnScalarType _ectdNoPrimaryKeyTableName "FirstName"
|
||||
let lastNameScalarType = _ectdFindColumnScalarType _ectdNoPrimaryKeyTableName "LastName"
|
||||
let whereExp =
|
||||
And
|
||||
[ ApplyBinaryComparisonOperator Equal (_ectdCurrentComparisonColumn "FirstName" firstNameScalarType) (ScalarValue (J.String "Beverly") firstNameScalarType),
|
||||
ApplyBinaryComparisonOperator Equal (_ectdCurrentComparisonColumn "LastName" lastNameScalarType) (ScalarValue (J.String "Crusher") lastNameScalarType)
|
||||
]
|
||||
let returning =
|
||||
Data.mkFieldsMap
|
||||
[ ("FirstName", _ectdColumnField _ectdNoPrimaryKeyTableName "FirstName"),
|
||||
("LastName", _ectdColumnField _ectdNoPrimaryKeyTableName "LastName")
|
||||
]
|
||||
let deleteOperation =
|
||||
mkDeleteOperation _ectdNoPrimaryKeyTableName
|
||||
& dmoWhere ?~ whereExp
|
||||
& dmoReturningFields .~ returning
|
||||
let mutationRequest = Data.emptyMutationRequest & mrOperations .~ [DeleteOperation deleteOperation]
|
||||
|
||||
response <- mutationGuarded mutationRequest
|
||||
|
||||
let expectedDeletedRows =
|
||||
[ Data.mkFieldsMap $
|
||||
[ ("FirstName", mkColumnFieldValue $ J.String "Beverly"),
|
||||
("LastName", mkColumnFieldValue $ J.String "Crusher")
|
||||
]
|
||||
]
|
||||
|
||||
let expectedResult = MutationOperationResults 1 (Just expectedDeletedRows)
|
||||
response `mutationResponseShouldBe` MutationResponse [expectedResult]
|
||||
where
|
||||
edgeCaseTest = Test.edgeCaseTest edgeCasesTestData
|
||||
|
||||
mkDeleteOperation :: TableName -> DeleteMutationOperation
|
||||
mkDeleteOperation tableName = DeleteMutationOperation tableName Nothing mempty
|
||||
|
||||
mkSubqueryResponse :: [HashMap FieldName FieldValue] -> FieldValue
|
||||
mkSubqueryResponse rows =
|
||||
mkRelationshipFieldValue $ QueryResponse (Just rows) Nothing
|
||||
|
||||
invoiceLinesFields :: HashMap FieldName Field
|
||||
invoiceLinesFields =
|
||||
Data.mkFieldsMap
|
||||
[ ("InvoiceId", _tdColumnField _tdInvoiceLinesTableName "InvoiceId"),
|
||||
("InvoiceLineId", _tdColumnField _tdInvoiceLinesTableName "InvoiceLineId"),
|
||||
("TrackId", _tdColumnField _tdInvoiceLinesTableName "TrackId"),
|
||||
("UnitPrice", _tdColumnField _tdInvoiceLinesTableName "UnitPrice"),
|
||||
("Quantity", _tdColumnField _tdInvoiceLinesTableName "Quantity")
|
||||
]
|
||||
|
||||
invoiceLinesQueryRequest :: QueryRequest
|
||||
invoiceLinesQueryRequest =
|
||||
let query = Data.emptyQuery & qFields ?~ invoiceLinesFields & qOrderBy ?~ OrderBy mempty (_tdOrderByColumn [] "InvoiceId" Ascending :| [])
|
||||
in QueryRequest _tdInvoiceLinesTableName [] query
|
||||
|
||||
invoiceIdScalarType = _tdFindColumnScalarType _tdInvoiceLinesTableName "InvoiceId"
|
||||
invoiceLineIdScalarType = _tdFindColumnScalarType _tdInvoiceLinesTableName "InvoiceLineId"
|
||||
composerScalarType = _tdFindColumnScalarType _tdTracksTableName "Composer"
|
Loading…
Reference in New Issue
Block a user