diff --git a/server/graphql-engine.cabal b/server/graphql-engine.cabal index 7ec054d1aa7..1abf4b7613b 100644 --- a/server/graphql-engine.cabal +++ b/server/graphql-engine.cabal @@ -1227,7 +1227,6 @@ test-suite tests-hspec -- Test Test.ArrayParamPermissionSpec - Test.ArrayRelationshipsSpec Test.BackendOnlyPermissionsSpec Test.BasicFieldsSpec Test.BigQuery.ComputedFieldSpec @@ -1264,7 +1263,6 @@ test-suite tests-hspec Test.LongIdentifiersSpec Test.NestedRelationshipsSpec Test.ObjectRelationshipsLimitSpec - Test.ObjectRelationshipsSpec Test.Queries.FilterSearchSpec Test.OrderingSpec Test.PostgresTypesSpec @@ -1280,6 +1278,8 @@ test-suite tests-hspec Test.RemoteRelationship.XToRemoteSchemaRelationshipSpec Test.RequestHeadersSpec Test.RunSQLSpec + Test.Schema.TableRelationships.ArrayRelationshipsSpec + Test.Schema.TableRelationships.ObjectRelationshipsSpec Test.Schema.DataValidation.PermissionSpec Test.SQLServer.InsertVarcharColumnSpec Test.SelectSpec diff --git a/server/tests-hspec/Harness/Test/BackendType.hs b/server/tests-hspec/Harness/Test/BackendType.hs index ca740d857ad..6de59b468d3 100644 --- a/server/tests-hspec/Harness/Test/BackendType.hs +++ b/server/tests-hspec/Harness/Test/BackendType.hs @@ -20,7 +20,7 @@ data BackendType | BigQuery | Citus | DataConnector - deriving (Show) + deriving (Eq, Show) -- | The default hasura metadata source name used for a given backend in this test suite project. defaultSource :: BackendType -> String diff --git a/server/tests-hspec/Test/ArrayRelationshipsSpec.hs b/server/tests-hspec/Test/ArrayRelationshipsSpec.hs deleted file mode 100644 index e0e9e872a19..00000000000 --- a/server/tests-hspec/Test/ArrayRelationshipsSpec.hs +++ /dev/null @@ -1,128 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - --- | Testing array relationships. -module Test.ArrayRelationshipsSpec (spec) where - -import Harness.Backend.Mysql as Mysql -import Harness.GraphqlEngine qualified as GraphqlEngine -import Harness.Quoter.Graphql -import Harness.Quoter.Yaml -import Harness.Test.Context qualified as Context -import Harness.Test.Schema (Table (..), table) -import Harness.Test.Schema qualified as Schema -import Harness.TestEnvironment (TestEnvironment) -import Test.Hspec -import Prelude - --------------------------------------------------------------------------------- --- Preamble - -spec :: SpecWith TestEnvironment -spec = - Context.run - [ Context.Context - { name = Context.Backend Context.MySQL, - mkLocalTestEnvironment = Context.noLocalTestEnvironment, - setup = Mysql.setup schema, - teardown = Mysql.teardown schema, - customOptions = Nothing - } - ] - tests - --------------------------------------------------------------------------------- --- Schema - -schema :: [Schema.Table] -schema = [author, article] - -author :: Schema.Table -author = - (table "author") - { tableColumns = - [ Schema.column "id" Schema.TInt, - Schema.column "name" Schema.TStr, - Schema.column "createdAt" Schema.TUTCTime - ], - tablePrimaryKey = ["id"], - tableData = - [ [Schema.VInt 1, Schema.VStr "Author 1", Schema.parseUTCTimeOrError "2017-09-21 09:39:44"], - [Schema.VInt 2, Schema.VStr "Author 2", Schema.parseUTCTimeOrError "2017-09-21 09:50:44"] - ] - } - -article :: Schema.Table -article = - (table "article") - { tableColumns = - [ Schema.column "id" Schema.TInt, - Schema.column "title" Schema.TStr, - Schema.column "content" Schema.TStr, - Schema.column "is_published" Schema.TBool, - Schema.column "published_on" Schema.TUTCTime, - Schema.columnNull "author_id" Schema.TInt, - Schema.columnNull "co_author_id" Schema.TInt - ], - tablePrimaryKey = ["id"], - tableReferences = - [ Schema.Reference "author_id" "author" "id", - Schema.Reference "co_author_id" "author" "id" - ], - tableData = - [ [ Schema.VInt 1, - Schema.VStr "Article 1", - Schema.VStr "Sample article content 1", - Schema.VBool False, - Schema.parseUTCTimeOrError "2022-01-01 00:00:00", - Schema.VInt 1, - Schema.VInt 2 - ], - [ Schema.VInt 2, - Schema.VStr "Article 2", - Schema.VStr "Sample article content 2", - Schema.VBool True, - Schema.parseUTCTimeOrError "2022-01-01 00:00:00", - Schema.VInt 1, - Schema.VInt 2 - ], - [ Schema.VInt 3, - Schema.VStr "Article 3", - Schema.VStr "Sample article content 3", - Schema.VBool True, - Schema.parseUTCTimeOrError "2022-01-01 00:00:00", - Schema.VInt 2, - Schema.VInt 1 - ] - ] - } - --------------------------------------------------------------------------------- --- Tests - -tests :: Context.Options -> SpecWith TestEnvironment -tests opts = do - it "Select an author and one of their articles" $ \testEnvironment -> - shouldReturnYaml - opts - ( GraphqlEngine.postGraphql - testEnvironment - [graphql| -query { - # we put id=1 restrictions here because we don't assume ordering support - hasura_author(where: {id: {_eq: 1}}) { - id - # the _by_id_to_author_id part is necessary to distinguish between multiple foreign key relationships between the same two tables - articles_by_id_to_author_id(where: {id: {_eq: 1}}) { - id - } - } -} -|] - ) - [yaml| -data: - hasura_author: - - id: 1 - articles_by_id_to_author_id: - - id: 1 -|] diff --git a/server/tests-hspec/Test/ObjectRelationshipsSpec.hs b/server/tests-hspec/Test/ObjectRelationshipsSpec.hs deleted file mode 100644 index cb72f2769af..00000000000 --- a/server/tests-hspec/Test/ObjectRelationshipsSpec.hs +++ /dev/null @@ -1,155 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - --- | Testing object relationships. -module Test.ObjectRelationshipsSpec (spec) where - -import Harness.Backend.Mysql qualified as Mysql -import Harness.Backend.Sqlserver qualified as Sqlserver -import Harness.GraphqlEngine qualified as GraphqlEngine -import Harness.Quoter.Graphql -import Harness.Quoter.Yaml -import Harness.Test.Context qualified as Context -import Harness.Test.Schema (Table (..), table) -import Harness.Test.Schema qualified as Schema -import Harness.TestEnvironment (TestEnvironment) -import Test.Hspec -import Prelude - --------------------------------------------------------------------------------- --- Preamble - -spec :: SpecWith TestEnvironment -spec = do - Context.run - [ Context.Context - { name = Context.Backend Context.SQLServer, - mkLocalTestEnvironment = Context.noLocalTestEnvironment, - setup = Sqlserver.setup schema, - teardown = Sqlserver.teardown schema, - customOptions = Nothing - } - ] - mssqlTests - - Context.run - [ Context.Context - { name = Context.Backend Context.MySQL, - mkLocalTestEnvironment = Context.noLocalTestEnvironment, - setup = Mysql.setup schema, - teardown = Mysql.teardown schema, - customOptions = Nothing - } - ] - mysqlTests - --------------------------------------------------------------------------------- --- Schema - -schema :: [Schema.Table] -schema = [author, article] - -author :: Schema.Table -author = - (table "author") - { tableColumns = - [ Schema.column "id" Schema.TInt, - Schema.column "name" Schema.TStr - ], - tablePrimaryKey = ["id"], - tableData = - [ [Schema.VInt 1, Schema.VStr "Author 1"], - [Schema.VInt 2, Schema.VStr "Author 2"] - ] - } - -article :: Schema.Table -article = - (table "article") - { tableColumns = - [ Schema.column "id" Schema.TInt, - Schema.columnNull "author_id" Schema.TInt - ], - tablePrimaryKey = ["id"], - tableReferences = [Schema.Reference "author_id" "author" "id"], - tableData = - [ [ Schema.VInt 1, - Schema.VInt 1 - ], - [ Schema.VInt 2, - Schema.VInt 1 - ], - [ Schema.VInt 3, - Schema.VInt 2 - ], - [ Schema.VInt 4, - Schema.VNull - ] - ] - } - --------------------------------------------------------------------------------- --- Tests - -mssqlTests :: Context.Options -> SpecWith TestEnvironment -mssqlTests opts = do - usingWhereClause opts - nullField opts - -mysqlTests :: Context.Options -> SpecWith TestEnvironment -mysqlTests opts = do - usingWhereClause opts - xdescribe - "Pending: The MySQL backend currently fails with relationship fields that are null.\ - \ (https://github.com/hasura/graphql-engine-mono/issues/3650)" - (nullField opts) - -usingWhereClause :: Context.Options -> SpecWith TestEnvironment -usingWhereClause opts = do - it "Author of article where id=1" $ \testEnvironment -> - shouldReturnYaml - opts - ( GraphqlEngine.postGraphql - testEnvironment - [graphql| -query { - hasura_article(where: {id: {_eq: 1}}) { - id - author_by_author_id_to_id { - id - } - } -} -|] - ) - [yaml| -data: - hasura_article: - - id: 1 - author_by_author_id_to_id: - id: 1 -|] - -nullField :: Context.Options -> SpecWith TestEnvironment -nullField opts = do - it "Can realise a null relationship field" $ \testEnvironment -> - shouldReturnYaml - opts - ( GraphqlEngine.postGraphql - testEnvironment - [graphql| -query { - hasura_article(where: {id: {_eq: 4}}) { - id - author_by_author_id_to_id { - id - } - } -} -|] - ) - [yaml| -data: - hasura_article: - - author_by_author_id_to_id: null - id: 4 -|] diff --git a/server/tests-hspec/Test/Schema/TableRelationships/ArrayRelationshipsSpec.hs b/server/tests-hspec/Test/Schema/TableRelationships/ArrayRelationshipsSpec.hs new file mode 100644 index 00000000000..bf01092961d --- /dev/null +++ b/server/tests-hspec/Test/Schema/TableRelationships/ArrayRelationshipsSpec.hs @@ -0,0 +1,152 @@ +{-# LANGUAGE QuasiQuotes #-} + +module Test.Schema.TableRelationships.ArrayRelationshipsSpec (spec) where + +import Data.Aeson (Value) +import Harness.Backend.BigQuery qualified as BigQuery +import Harness.Backend.Citus qualified as Citus +import Harness.Backend.Mysql qualified as Mysql +import Harness.Backend.Postgres qualified as Postgres +import Harness.Backend.Sqlserver qualified as Sqlserver +import Harness.GraphqlEngine (postGraphql) +import Harness.Quoter.Graphql (graphql) +import Harness.Quoter.Yaml (shouldReturnYaml, yaml) +import Harness.Test.Context qualified as Context +import Harness.Test.Schema (Table (..), table) +import Harness.Test.Schema qualified as Schema +import Harness.TestEnvironment (TestEnvironment) +import Test.Hspec (SpecWith, describe, it) +import Prelude + +spec :: SpecWith TestEnvironment +spec = do + Context.run + [ Context.Context + { name = Context.Backend Context.MySQL, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = Mysql.setup schema, + teardown = Mysql.teardown schema, + customOptions = Nothing + }, + Context.Context + { name = Context.Backend Context.Postgres, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = Postgres.setup schema, + teardown = Postgres.teardown schema, + customOptions = Nothing + }, + Context.Context + { name = Context.Backend Context.Citus, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = Citus.setup schema, + teardown = Citus.teardown schema, + customOptions = Nothing + }, + Context.Context + { name = Context.Backend Context.SQLServer, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = Sqlserver.setup schema, + teardown = Sqlserver.teardown schema, + customOptions = Nothing + }, + Context.Context + { name = Context.Backend Context.BigQuery, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = BigQuery.setup schema, + teardown = BigQuery.teardown schema, + customOptions = + Just $ + Context.Options + { stringifyNumbers = True + } + } + ] + tests + +-------------------------------------------------------------------------------- +-- Schema + +schema :: [Schema.Table] +schema = + [ (table "author") + { tableColumns = + [ Schema.column "id" Schema.TInt, + Schema.column "name" Schema.TStr + ], + tablePrimaryKey = ["id"], + tableData = + [ [Schema.VInt 1, Schema.VStr "Author 1"], + [Schema.VInt 2, Schema.VStr "Author 2"] + ] + }, + (table "article") + { tableColumns = + [ Schema.column "id" Schema.TInt, + Schema.column "title" Schema.TStr, + Schema.column "author_id" Schema.TInt + ], + tablePrimaryKey = ["id"], + tableReferences = + [ Schema.Reference "author_id" "author" "id" + ], + tableData = + [ [ Schema.VInt 1, + Schema.VStr "Article 1", + Schema.VInt 1 + ], + [ Schema.VInt 2, + Schema.VStr "Article 2", + Schema.VInt 1 + ], + [ Schema.VInt 3, + Schema.VStr "Article 3", + Schema.VInt 2 + ] + ] + } + ] + +-------------------------------------------------------------------------------- +-- Tests + +tests :: Context.Options -> SpecWith TestEnvironment +tests opts = do + let shouldBe :: IO Value -> Value -> IO () + shouldBe = shouldReturnYaml opts + + describe "Array relationships" do + it "Select authors and their articles" \testEnvironment -> do + let expected :: Value + expected = + [yaml| + data: + hasura_author: + - id: 1 + articles_by_id_to_author_id: + - id: 1 + - id: 2 + + - id: 2 + articles_by_id_to_author_id: + - id: 3 + |] + + -- We have to provide explicit orderings because BigQuery doesn't + -- seem to return results in a deterministic order. + actual :: IO Value + actual = + postGraphql + testEnvironment + [graphql| + query { + hasura_author(order_by: [{ id: asc }]) { + id + + articles_by_id_to_author_id(order_by: [{ id: asc }]) { + id + } + } + } + |] + + actual `shouldBe` expected diff --git a/server/tests-hspec/Test/Schema/TableRelationships/ObjectRelationshipsSpec.hs b/server/tests-hspec/Test/Schema/TableRelationships/ObjectRelationshipsSpec.hs new file mode 100644 index 00000000000..86593885399 --- /dev/null +++ b/server/tests-hspec/Test/Schema/TableRelationships/ObjectRelationshipsSpec.hs @@ -0,0 +1,218 @@ +{-# LANGUAGE QuasiQuotes #-} + +-- | +-- Queries over object relationships between tables in the schema. +-- +-- TODO: MySQL link when docs are released? +-- https://hasura.io/docs/latest/schema/postgres/table-relationships/index +-- https://hasura.io/docs/latest/schema/ms-sql-server/table-relationships/index +-- https://hasura.io/docs/latest/schema/bigquery/table-relationships/index/ +module Test.Schema.TableRelationships.ObjectRelationshipsSpec (spec) where + +import Control.Monad (unless) +import Data.Aeson (Value) +import Harness.Backend.BigQuery qualified as BigQuery +import Harness.Backend.Mysql qualified as Mysql +import Harness.Backend.Postgres qualified as Postgres +import Harness.GraphqlEngine (postGraphql) +import Harness.Quoter.Graphql (graphql) +import Harness.Quoter.Yaml (shouldReturnYaml, yaml) +import Harness.Test.BackendType (BackendType (..)) +import Harness.Test.Context (Options (..)) +import Harness.Test.Context qualified as Context +import Harness.Test.Schema (Table (..), table) +import Harness.Test.Schema qualified as Schema +import Harness.TestEnvironment (TestEnvironment) +import Test.Hspec (SpecWith, describe, it) +import Prelude + +spec :: SpecWith TestEnvironment +spec = do + Context.run + [ Context.Context + { name = Context.Backend Context.MySQL, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = Mysql.setup schema, + teardown = Mysql.teardown schema, + customOptions = Nothing + } + ] + $ tests MySQL + + Context.run + [ Context.Context + { name = Context.Backend Context.Postgres, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = Postgres.setup schema, + teardown = Postgres.teardown schema, + customOptions = Nothing + } + ] + $ tests Postgres + + -- Context.run + -- [ Context.Context + -- { name = Context.Backend Context.Citus, + -- mkLocalTestEnvironment = Context.noLocalTestEnvironment, + -- setup = Citus.setup schema, + -- teardown = Citus.teardown schema, + -- customOptions = Nothing + -- } + -- ] + -- $ tests Citus + + -- Context.run + -- [ Context.Context + -- { name = Context.Backend Context.SQLServer, + -- mkLocalTestEnvironment = Context.noLocalTestEnvironment, + -- setup = Sqlserver.setup schema, + -- teardown = Sqlserver.teardown schema, + -- customOptions = Nothing + -- } + -- ] + -- $ tests SQLServer + + Context.run + [ Context.Context + { name = Context.Backend Context.BigQuery, + mkLocalTestEnvironment = Context.noLocalTestEnvironment, + setup = BigQuery.setup schema, + teardown = BigQuery.teardown schema, + customOptions = + Just $ + Context.Options + { stringifyNumbers = True + } + } + ] + $ tests BigQuery + +-------------------------------------------------------------------------------- +-- Schema + +schema :: [Schema.Table] +schema = + [ (table "author") + { tableColumns = + [ Schema.column "id" Schema.TInt, + Schema.column "name" Schema.TStr + ], + tablePrimaryKey = ["id"], + tableData = + [ [Schema.VInt 1, Schema.VStr "Author 1"], + [Schema.VInt 2, Schema.VStr "Author 2"] + ] + }, + (table "article") + { tableColumns = + [ Schema.column "id" Schema.TInt, + Schema.column "title" Schema.TStr, + Schema.column "author_id" Schema.TInt, + Schema.columnNull "co_author_id" Schema.TInt + ], + tablePrimaryKey = ["id"], + tableReferences = + [ Schema.Reference "author_id" "author" "id", + Schema.Reference "co_author_id" "author" "id" + ], + tableData = + [ [ Schema.VInt 1, + Schema.VStr "Article 1", + Schema.VInt 1, + Schema.VNull + ], + [ Schema.VInt 2, + Schema.VStr "Article 2", + Schema.VInt 1, + Schema.VNull + ], + [ Schema.VInt 3, + Schema.VStr "Article 3", + Schema.VInt 2, + Schema.VInt 1 + ] + ] + } + ] + +-------------------------------------------------------------------------------- +-- Tests + +tests :: BackendType -> Context.Options -> SpecWith TestEnvironment +tests backend opts = describe "Object relationships" do + let shouldBe :: IO Value -> Value -> IO () + shouldBe = shouldReturnYaml opts + + it "Select articles and their authors" \testEnvironment -> do + let expected :: Value + expected = + [yaml| + data: + hasura_article: + - id: 1 + author_by_author_id_to_id: + id: 1 + + - id: 2 + author_by_author_id_to_id: + id: 1 + + - id: 3 + author_by_author_id_to_id: + id: 2 + |] + + -- We have to provide explicit orderings because BigQuery doesn't + -- seem to return results in a deterministic order. + actual :: IO Value + actual = + postGraphql + testEnvironment + [graphql| + query { + hasura_article(order_by: [{ id: asc }]) { + id + + author_by_author_id_to_id { + id + } + } + } + |] + + actual `shouldBe` expected + + unless (backend `elem` [MySQL, BigQuery]) do + describe "Null relationships" do + it "Select articles their (possibly null) co-authors" \testEnvironment -> do + let expected :: Value + expected = + [yaml| + data: + hasura_article: + - id: 1 + author_by_co_author_id_to_id: null + - id: 2 + author_by_co_author_id_to_id: null + - id: 3 + author_by_co_author_id_to_id: + id: 1 + |] + + actual :: IO Value + actual = + postGraphql + testEnvironment + [graphql| + query { + hasura_article(order_by: [{ id: asc }]) { + id + + author_by_co_author_id_to_id { + id + } + } + } + |] + + actual `shouldBe` expected