mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-20 14:01:39 +03:00
f05f746b94
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6095 Co-authored-by: Gil Mizrahi <8547573+soupi@users.noreply.github.com> GitOrigin-RevId: 51693f7324e62e201a2bdc701255cf6c730745e2
442 lines
13 KiB
Haskell
442 lines
13 KiB
Haskell
{-# LANGUAGE QuasiQuotes #-}
|
|
|
|
module Test.DataConnector.AggregateQuerySpec
|
|
( spec,
|
|
)
|
|
where
|
|
|
|
import Data.Aeson qualified as Aeson
|
|
import Harness.Backend.DataConnector qualified as DataConnector
|
|
import Harness.GraphqlEngine qualified as GraphqlEngine
|
|
import Harness.Quoter.Graphql (graphql)
|
|
import Harness.Quoter.Yaml (yaml)
|
|
import Harness.Test.BackendType (BackendType (..), defaultBackendTypeString, defaultSource)
|
|
import Harness.Test.Fixture qualified as Fixture
|
|
import Harness.TestEnvironment (TestEnvironment)
|
|
import Harness.TestEnvironment qualified as TE
|
|
import Harness.Yaml (shouldReturnYaml)
|
|
import Hasura.Prelude
|
|
import Test.Hspec (SpecWith, describe, it)
|
|
|
|
spec :: SpecWith TestEnvironment
|
|
spec =
|
|
Fixture.runWithLocalTestEnvironment
|
|
( ( \(DataConnector.TestSourceConfig backendType backendConfig sourceConfig _md) ->
|
|
(Fixture.fixture $ Fixture.Backend backendType)
|
|
{ Fixture.setupTeardown =
|
|
\(testEnv, _) -> [DataConnector.setupFixtureAction (sourceMetadata backendType sourceConfig) backendConfig testEnv]
|
|
}
|
|
)
|
|
<$> DataConnector.backendConfigs
|
|
)
|
|
tests
|
|
|
|
sourceMetadata :: BackendType -> Aeson.Value -> Aeson.Value
|
|
sourceMetadata backendType config =
|
|
let source = defaultSource backendType
|
|
backendTypeString = defaultBackendTypeString backendType
|
|
in [yaml|
|
|
name : *source
|
|
kind: *backendTypeString
|
|
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: *config
|
|
|]
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
tests :: Fixture.Options -> SpecWith (TestEnvironment, a)
|
|
tests opts = describe "Aggregate Query Tests" $ do
|
|
describe "Nodes Tests" $ do
|
|
it "works with simple query" $ \(testEnvironment, _) ->
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getAlbum {
|
|
Album_aggregate(limit: 2) {
|
|
nodes {
|
|
AlbumId
|
|
Title
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Album_aggregate:
|
|
nodes:
|
|
- AlbumId: 1
|
|
Title: For Those About To Rock We Salute You
|
|
- AlbumId: 2
|
|
Title: Balls to the Wall
|
|
|]
|
|
|
|
it "works with multiple nodes fields" $ \(testEnvironment, _) ->
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getAlbum {
|
|
Album_aggregate(limit: 2) {
|
|
AlbumIds: nodes {
|
|
AlbumId
|
|
}
|
|
Titles: nodes {
|
|
Title
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Album_aggregate:
|
|
AlbumIds:
|
|
- AlbumId: 1
|
|
- AlbumId: 2
|
|
Titles:
|
|
- Title: For Those About To Rock We Salute You
|
|
- Title: Balls to the Wall
|
|
|]
|
|
|
|
it "works with object relations" $ \(testEnvironment, _) -> do
|
|
-- NOTE: Ordering is required due to datasets non-matching orders
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getAlbum {
|
|
Album_aggregate(order_by: {AlbumId: asc}, limit: 2) {
|
|
nodes {
|
|
AlbumId
|
|
Artist {
|
|
Name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Album_aggregate:
|
|
nodes:
|
|
- AlbumId: 1
|
|
Artist:
|
|
Name: AC/DC
|
|
- AlbumId: 2
|
|
Artist:
|
|
Name: Accept
|
|
|]
|
|
|
|
it "works with array relations" $ \(testEnvironment, _) ->
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getArtist {
|
|
Artist_aggregate(limit: 2) {
|
|
nodes {
|
|
ArtistId
|
|
Albums: Albums_aggregate {
|
|
nodes {
|
|
Title
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Artist_aggregate:
|
|
nodes:
|
|
- ArtistId: 1
|
|
Albums:
|
|
nodes:
|
|
- Title: For Those About To Rock We Salute You
|
|
- Title: Let There Be Rock
|
|
- ArtistId: 2
|
|
Albums:
|
|
nodes:
|
|
- Title: Balls to the Wall
|
|
- Title: Restless and Wild
|
|
|]
|
|
|
|
describe "Aggregate Tests" $ do
|
|
it "works with count queries" $ \(testEnvironment, _) ->
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getInvoices {
|
|
Invoice_aggregate {
|
|
aggregate {
|
|
count
|
|
countColumn: count(column: BillingState)
|
|
countColumnDistinct: count(column: BillingState, distinct: true)
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Invoice_aggregate:
|
|
aggregate:
|
|
count: 412
|
|
countColumn: 210
|
|
countColumnDistinct: 25
|
|
|]
|
|
|
|
it "works with single column queries" $ \(testEnvironment, _) -> do
|
|
-- NOTE: This test is specialized for the reference agent to support more statistical functions.
|
|
-- This should really be derived from the agent's capabilities.
|
|
let referenceQuery =
|
|
[graphql|
|
|
query getInvoices {
|
|
Invoice_aggregate {
|
|
aggregate {
|
|
max { Total }
|
|
min { Total }
|
|
stddev { Total }
|
|
stddev_pop { Total }
|
|
stddev_samp { Total }
|
|
sum { Total }
|
|
var_pop { Total }
|
|
var_samp { Total }
|
|
variance { Total }
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
|
|
generalQuery =
|
|
[graphql|
|
|
query getInvoices {
|
|
Invoice_aggregate {
|
|
aggregate {
|
|
max { Total }
|
|
min { Total }
|
|
sum { Total }
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
|
|
referenceResults =
|
|
[yaml|
|
|
data:
|
|
Invoice_aggregate:
|
|
aggregate:
|
|
max:
|
|
Total: 25.86
|
|
min:
|
|
Total: 0.99
|
|
stddev:
|
|
Total: 4.745319693568103
|
|
stddev_pop:
|
|
Total: 4.739557311729622
|
|
stddev_samp:
|
|
Total: 4.745319693568103
|
|
sum:
|
|
Total: 2328.600000000004
|
|
var_pop:
|
|
Total: 22.463403511169727
|
|
var_samp:
|
|
Total: 22.518058994165273
|
|
variance:
|
|
Total: 22.518058994165273
|
|
|]
|
|
|
|
generalResults =
|
|
[yaml|
|
|
data:
|
|
Invoice_aggregate:
|
|
aggregate:
|
|
max:
|
|
Total: 25.86
|
|
min:
|
|
Total: 0.99
|
|
sum:
|
|
Total: 2328.6
|
|
|]
|
|
|
|
if (TE.backendType testEnvironment == Just Fixture.DataConnectorReference)
|
|
then
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
referenceQuery
|
|
)
|
|
referenceResults
|
|
else
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
generalQuery
|
|
)
|
|
generalResults
|
|
|
|
it "min and max works on string fields" $ \(testEnvironment, _) ->
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getArtists {
|
|
Artist_aggregate {
|
|
aggregate {
|
|
max {
|
|
Name
|
|
}
|
|
min {
|
|
Name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Artist_aggregate:
|
|
aggregate:
|
|
max:
|
|
Name: Zeca Pagodinho
|
|
min:
|
|
Name: A Cor Do Som
|
|
|]
|
|
|
|
it "works across array relationships from regular queries" $ \(testEnvironment, _) -> do
|
|
-- NOTE: Ordering is added to allow SQLite chinook dataset to return ordered results
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getInvoices {
|
|
Invoice(limit: 5, order_by: {InvoiceId: asc}) {
|
|
InvoiceId
|
|
InvoiceLines_aggregate {
|
|
aggregate {
|
|
count
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Invoice:
|
|
- InvoiceId: 1
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 2
|
|
- InvoiceId: 2
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 4
|
|
- InvoiceId: 3
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 6
|
|
- InvoiceId: 4
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 9
|
|
- InvoiceId: 5
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 14
|
|
|]
|
|
|
|
it "works across array relationships from aggregate queries via nodes" $ \(testEnvironment, _) -> do
|
|
-- NOTE: Ordering present so that out-of-order rows are sorted for SQLite
|
|
shouldReturnYaml
|
|
opts
|
|
( GraphqlEngine.postGraphql
|
|
testEnvironment
|
|
[graphql|
|
|
query getInvoices {
|
|
Invoice_aggregate(limit: 5, order_by: {InvoiceId: asc}) {
|
|
nodes {
|
|
InvoiceId
|
|
InvoiceLines_aggregate {
|
|
aggregate {
|
|
count
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|]
|
|
)
|
|
[yaml|
|
|
data:
|
|
Invoice_aggregate:
|
|
nodes:
|
|
- InvoiceId: 1
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 2
|
|
- InvoiceId: 2
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 4
|
|
- InvoiceId: 3
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 6
|
|
- InvoiceId: 4
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 9
|
|
- InvoiceId: 5
|
|
InvoiceLines_aggregate:
|
|
aggregate:
|
|
count: 14
|
|
|]
|