mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-24 16:03:37 +03:00
c209b60239
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5329 GitOrigin-RevId: 5cf492bc2b09fef6250f4dd50f74f750f55ebe6a
337 lines
15 KiB
Haskell
337 lines
15 KiB
Haskell
{-# LANGUAGE QuasiQuotes #-}
|
|
|
|
module Test.DataConnector.MockAgent.AggregateQuerySpec
|
|
( spec,
|
|
)
|
|
where
|
|
|
|
import Data.Aeson qualified as Aeson
|
|
import Data.Aeson.KeyMap qualified as KM
|
|
import Data.HashMap.Strict qualified as HashMap
|
|
import Data.List.NonEmpty qualified as NE
|
|
import Harness.Backend.DataConnector (TestCase (..))
|
|
import Harness.Backend.DataConnector qualified as DataConnector
|
|
import Harness.Quoter.Graphql (graphql)
|
|
import Harness.Quoter.Yaml (yaml)
|
|
import Harness.Test.BackendType (BackendType (..), defaultBackendTypeString, defaultSource)
|
|
import Harness.Test.Context qualified as Context
|
|
import Harness.TestEnvironment (TestEnvironment)
|
|
import Hasura.Backends.DataConnector.API qualified as API
|
|
import Hasura.Prelude
|
|
import Test.Hspec (SpecWith, describe, it)
|
|
|
|
spec :: SpecWith TestEnvironment
|
|
spec =
|
|
Context.runWithLocalTestEnvironment
|
|
( NE.fromList
|
|
[ Context.Context
|
|
{ name = Context.Backend Context.DataConnector,
|
|
mkLocalTestEnvironment = DataConnector.mkLocalTestEnvironmentMock,
|
|
setup = DataConnector.setupMock sourceMetadata DataConnector.mockBackendConfig,
|
|
teardown = DataConnector.teardownMock,
|
|
customOptions = Nothing
|
|
}
|
|
]
|
|
)
|
|
tests
|
|
|
|
sourceMetadata :: Aeson.Value
|
|
sourceMetadata =
|
|
let source = defaultSource DataConnector
|
|
backendType = defaultBackendTypeString DataConnector
|
|
in [yaml|
|
|
name : *source
|
|
kind: *backendType
|
|
tables:
|
|
- table: [Album]
|
|
object_relationships:
|
|
- name: Artist
|
|
using:
|
|
manual_configuration:
|
|
remote_table: [Artist]
|
|
column_mapping:
|
|
ArtistId: ArtistId
|
|
- table: [Artist]
|
|
array_relationships:
|
|
- name: Albums
|
|
using:
|
|
manual_configuration:
|
|
remote_table: [Album]
|
|
column_mapping:
|
|
ArtistId: ArtistId
|
|
- table: [Invoice]
|
|
array_relationships:
|
|
- name: InvoiceLines
|
|
using:
|
|
manual_configuration:
|
|
remote_table: [InvoiceLine]
|
|
column_mapping:
|
|
InvoiceId: InvoiceId
|
|
- table: [InvoiceLine]
|
|
object_relationships:
|
|
- name: Invoice
|
|
using:
|
|
manual_configuration:
|
|
remote_table: [Invoice]
|
|
column_mapping:
|
|
InvoiceId: InvoiceId
|
|
configuration: {}
|
|
|]
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
tests :: Context.Options -> SpecWith (TestEnvironment, DataConnector.MockAgentEnvironment)
|
|
tests opts = describe "Aggregate Query Tests" $ do
|
|
it "works with multiple nodes fields and through array relations" $
|
|
DataConnector.runMockedTest opts $
|
|
let required =
|
|
DataConnector.TestCaseRequired
|
|
{ _givenRequired =
|
|
let response =
|
|
[ [ ("ArtistIds_Id", API.mkColumnFieldValue $ Aeson.Number 1),
|
|
("ArtistNames_Name", API.mkColumnFieldValue $ Aeson.String "AC/DC"),
|
|
( "nodes_Albums",
|
|
API.mkRelationshipFieldValue $
|
|
rowsResponse
|
|
[ [("nodes_Title", API.mkColumnFieldValue $ Aeson.String "For Those About To Rock We Salute You")],
|
|
[("nodes_Title", API.mkColumnFieldValue $ Aeson.String "Let There Be Rock")]
|
|
]
|
|
)
|
|
]
|
|
]
|
|
in DataConnector.chinookMock {DataConnector._queryResponse = \_ -> rowsResponse response},
|
|
_whenRequestRequired =
|
|
[graphql|
|
|
query getArtist {
|
|
Artist_aggregate(limit: 1) {
|
|
ArtistIds: nodes {
|
|
Id: ArtistId
|
|
}
|
|
ArtistNames: nodes {
|
|
Name
|
|
}
|
|
nodes {
|
|
Albums: Albums_aggregate {
|
|
nodes {
|
|
Title
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|],
|
|
_thenRequired =
|
|
[yaml|
|
|
data:
|
|
Artist_aggregate:
|
|
ArtistIds:
|
|
- Id: 1
|
|
ArtistNames:
|
|
- Name: AC/DC
|
|
nodes:
|
|
- Albums:
|
|
nodes:
|
|
- Title: For Those About To Rock We Salute You
|
|
- Title: Let There Be Rock
|
|
|]
|
|
}
|
|
in (DataConnector.defaultTestCase required)
|
|
{ _whenQuery =
|
|
Just
|
|
( API.QueryRequest
|
|
{ _qrTable = API.TableName ("Artist" :| []),
|
|
_qrTableRelationships =
|
|
[ API.TableRelationships
|
|
{ _trSourceTable = API.TableName ("Artist" :| []),
|
|
_trRelationships =
|
|
HashMap.fromList
|
|
[ ( API.RelationshipName "Albums",
|
|
API.Relationship
|
|
{ _rTargetTable = API.TableName ("Album" :| []),
|
|
_rRelationshipType = API.ArrayRelationship,
|
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "ArtistId", API.ColumnName "ArtistId")]
|
|
}
|
|
)
|
|
]
|
|
}
|
|
],
|
|
_qrQuery =
|
|
API.Query
|
|
{ _qFields =
|
|
Just $
|
|
KM.fromList
|
|
[ ("ArtistIds_Id", API.ColumnField (API.ColumnName "ArtistId")),
|
|
("ArtistNames_Name", API.ColumnField (API.ColumnName "Name")),
|
|
( "nodes_Albums",
|
|
API.RelField
|
|
( API.RelationshipField
|
|
(API.RelationshipName "Albums")
|
|
API.Query
|
|
{ _qFields =
|
|
Just $
|
|
KM.fromList
|
|
[ ("nodes_Title", API.ColumnField (API.ColumnName "Title"))
|
|
],
|
|
_qAggregates = Nothing,
|
|
_qLimit = Nothing,
|
|
_qOffset = Nothing,
|
|
_qWhere = Just (API.And []),
|
|
_qOrderBy = Nothing
|
|
}
|
|
)
|
|
)
|
|
],
|
|
_qAggregates = Nothing,
|
|
_qLimit = Just 1,
|
|
_qOffset = Nothing,
|
|
_qWhere = Just (API.And []),
|
|
_qOrderBy = Nothing
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
it "works with multiple aggregate fields and through array relations" $
|
|
DataConnector.runMockedTest opts $
|
|
let required =
|
|
DataConnector.TestCaseRequired
|
|
{ _givenRequired =
|
|
let aggregates =
|
|
[ ("counts_count", API.Number 2),
|
|
("counts_uniqueBillingCountries", API.Number 2),
|
|
("ids_minimum_Id", API.Number 1),
|
|
("ids_max_InvoiceId", API.Number 2)
|
|
]
|
|
rows =
|
|
[ [ ( "nodes_Lines",
|
|
API.mkRelationshipFieldValue $
|
|
aggregatesResponse
|
|
[ ("aggregate_count", API.Number 2)
|
|
]
|
|
)
|
|
],
|
|
[ ( "nodes_Lines",
|
|
API.mkRelationshipFieldValue $
|
|
aggregatesResponse
|
|
[ ("aggregate_count", API.Number 4)
|
|
]
|
|
)
|
|
]
|
|
]
|
|
in DataConnector.chinookMock {DataConnector._queryResponse = \_ -> aggregatesAndRowsResponse aggregates rows},
|
|
_whenRequestRequired =
|
|
[graphql|
|
|
query getInvoices {
|
|
Invoice_aggregate(limit: 2) {
|
|
counts: aggregate {
|
|
count
|
|
uniqueBillingCountries: count(column: BillingCountry, distinct: true)
|
|
}
|
|
ids: aggregate {
|
|
minimum: min {
|
|
Id: InvoiceId
|
|
}
|
|
max {
|
|
InvoiceId
|
|
}
|
|
}
|
|
nodes {
|
|
Lines: InvoiceLines_aggregate {
|
|
aggregate {
|
|
count
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|],
|
|
_thenRequired =
|
|
[yaml|
|
|
data:
|
|
Invoice_aggregate:
|
|
counts:
|
|
count: 2
|
|
uniqueBillingCountries: 2
|
|
ids:
|
|
minimum:
|
|
Id: 1
|
|
max:
|
|
InvoiceId: 2
|
|
nodes:
|
|
- Lines:
|
|
aggregate:
|
|
count: 2
|
|
- Lines:
|
|
aggregate:
|
|
count: 4
|
|
|]
|
|
}
|
|
in (DataConnector.defaultTestCase required)
|
|
{ _whenQuery =
|
|
Just
|
|
( API.QueryRequest
|
|
{ _qrTable = API.TableName ("Invoice" :| []),
|
|
_qrTableRelationships =
|
|
[ API.TableRelationships
|
|
{ _trSourceTable = API.TableName ("Invoice" :| []),
|
|
_trRelationships =
|
|
HashMap.fromList
|
|
[ ( API.RelationshipName "InvoiceLines",
|
|
API.Relationship
|
|
{ _rTargetTable = API.TableName ("InvoiceLine" :| []),
|
|
_rRelationshipType = API.ArrayRelationship,
|
|
_rColumnMapping = HashMap.fromList [(API.ColumnName "InvoiceId", API.ColumnName "InvoiceId")]
|
|
}
|
|
)
|
|
]
|
|
}
|
|
],
|
|
_qrQuery =
|
|
API.Query
|
|
{ _qFields =
|
|
Just $
|
|
KM.fromList
|
|
[ ( "nodes_Lines",
|
|
API.RelField
|
|
( API.RelationshipField
|
|
(API.RelationshipName "InvoiceLines")
|
|
API.Query
|
|
{ _qFields = Nothing,
|
|
_qAggregates =
|
|
Just $
|
|
KM.fromList
|
|
[("aggregate_count", API.StarCount)],
|
|
_qLimit = Nothing,
|
|
_qOffset = Nothing,
|
|
_qWhere = Just (API.And []),
|
|
_qOrderBy = Nothing
|
|
}
|
|
)
|
|
)
|
|
],
|
|
_qAggregates =
|
|
Just $
|
|
KM.fromList
|
|
[ ("counts_count", API.StarCount),
|
|
("counts_uniqueBillingCountries", API.ColumnCount (API.ColumnCountAggregate (API.ColumnName "BillingCountry") True)),
|
|
("ids_minimum_Id", API.SingleColumn (API.SingleColumnAggregate API.Min (API.ColumnName "InvoiceId"))),
|
|
("ids_max_InvoiceId", API.SingleColumn (API.SingleColumnAggregate API.Max (API.ColumnName "InvoiceId")))
|
|
],
|
|
_qLimit = Just 2,
|
|
_qOffset = Nothing,
|
|
_qWhere = Just (API.And []),
|
|
_qOrderBy = Nothing
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
rowsResponse :: [[(Aeson.Key, API.FieldValue)]] -> API.QueryResponse
|
|
rowsResponse rows = API.QueryResponse (Just $ KM.fromList <$> rows) Nothing
|
|
|
|
aggregatesResponse :: [(Aeson.Key, API.Value)] -> API.QueryResponse
|
|
aggregatesResponse aggregates = API.QueryResponse Nothing (Just $ KM.fromList aggregates)
|
|
|
|
aggregatesAndRowsResponse :: [(Aeson.Key, API.Value)] -> [[(Aeson.Key, API.FieldValue)]] -> API.QueryResponse
|
|
aggregatesAndRowsResponse aggregates rows = API.QueryResponse (Just $ KM.fromList <$> rows) (Just $ KM.fromList aggregates)
|