mirror of
https://github.com/hasura/graphql-engine.git
synced 2025-01-07 08:13:18 +03:00
chore(server): add tests/support for inserting JSON arrays
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9704 GitOrigin-RevId: 4c2820c302d056bed92bf61e3670419c6da1563e
This commit is contained in:
parent
90048c84bf
commit
cb02a9a034
@ -62,6 +62,11 @@ ghcid-api-tests-run: start-api-tests-backends
|
|||||||
ghcid-test-harness:
|
ghcid-test-harness:
|
||||||
$(call run_ghcid,test-harness)
|
$(call run_ghcid,test-harness)
|
||||||
|
|
||||||
|
.PHONY: ghcid-pg-client
|
||||||
|
## ghcid-pg-client: build and watch pg-client in ghcid
|
||||||
|
ghcid-pg-client:
|
||||||
|
$(call run_ghcid,pg-client)
|
||||||
|
|
||||||
.PHONY: ghcid-api-tests-pro
|
.PHONY: ghcid-api-tests-pro
|
||||||
## ghcid-api-tests-pro: build and watch api-tests in pro
|
## ghcid-api-tests-pro: build and watch api-tests in pro
|
||||||
ghcid-api-tests-pro:
|
ghcid-api-tests-pro:
|
||||||
|
@ -9,9 +9,9 @@ import Data.List.NonEmpty qualified as NE
|
|||||||
import Harness.Backend.Citus qualified as Citus
|
import Harness.Backend.Citus qualified as Citus
|
||||||
import Harness.Backend.Cockroach qualified as Cockroach
|
import Harness.Backend.Cockroach qualified as Cockroach
|
||||||
import Harness.Backend.Postgres qualified as Postgres
|
import Harness.Backend.Postgres qualified as Postgres
|
||||||
import Harness.GraphqlEngine (postGraphql)
|
import Harness.GraphqlEngine (postGraphql, postGraphqlWithVariables)
|
||||||
import Harness.Quoter.Graphql (graphql)
|
import Harness.Quoter.Graphql (graphql)
|
||||||
import Harness.Quoter.Yaml (interpolateYaml)
|
import Harness.Quoter.Yaml (interpolateYaml, yaml)
|
||||||
import Harness.Schema qualified as Schema
|
import Harness.Schema qualified as Schema
|
||||||
import Harness.Test.Fixture qualified as Fixture
|
import Harness.Test.Fixture qualified as Fixture
|
||||||
import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
|
||||||
@ -60,6 +60,23 @@ spec = do
|
|||||||
)
|
)
|
||||||
nestedArrayTests
|
nestedArrayTests
|
||||||
|
|
||||||
|
-- CockroachDB does not support json arrays
|
||||||
|
Fixture.run
|
||||||
|
( NE.fromList
|
||||||
|
[ (Fixture.fixture $ Fixture.Backend Postgres.backendTypeMetadata)
|
||||||
|
{ Fixture.setupTeardown = \(testEnv, _) ->
|
||||||
|
[ Postgres.setupTablesAction schema testEnv
|
||||||
|
]
|
||||||
|
},
|
||||||
|
(Fixture.fixture $ Fixture.Backend Citus.backendTypeMetadata)
|
||||||
|
{ Fixture.setupTeardown = \(testEnv, _) ->
|
||||||
|
[ Citus.setupTablesAction schema testEnv
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
jsonArrayTests
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- Schema
|
-- Schema
|
||||||
|
|
||||||
@ -72,13 +89,22 @@ textArrayType =
|
|||||||
Schema.bstCockroach = Just "text[]"
|
Schema.bstCockroach = Just "text[]"
|
||||||
}
|
}
|
||||||
|
|
||||||
nestedTextArrayType :: Schema.ScalarType
|
nestedIntArrayType :: Schema.ScalarType
|
||||||
nestedTextArrayType =
|
nestedIntArrayType =
|
||||||
Schema.TCustomType
|
Schema.TCustomType
|
||||||
$ Schema.defaultBackendScalarType
|
$ Schema.defaultBackendScalarType
|
||||||
{ Schema.bstPostgres = Just "text[][]",
|
{ Schema.bstPostgres = Just "int[][]",
|
||||||
Schema.bstCitus = Just "text[][]",
|
Schema.bstCitus = Just "int[][]",
|
||||||
Schema.bstCockroach = Just "text[]" -- nested arrays aren't supported in Cockroach, so we'll skip this test anyway
|
Schema.bstCockroach = Just "int[]" -- nested arrays aren't supported in Cockroach, so we'll skip this test anyway
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonArrayType :: Schema.ScalarType
|
||||||
|
jsonArrayType =
|
||||||
|
Schema.TCustomType
|
||||||
|
$ Schema.defaultBackendScalarType
|
||||||
|
{ Schema.bstPostgres = Just "json[]",
|
||||||
|
Schema.bstCitus = Just "json[]",
|
||||||
|
Schema.bstCockroach = Just "json" -- arrays of json aren't supported in Cockroach, so we'll skip this test
|
||||||
}
|
}
|
||||||
|
|
||||||
schema :: [Schema.Table]
|
schema :: [Schema.Table]
|
||||||
@ -88,7 +114,8 @@ schema =
|
|||||||
[ Schema.column "id" Schema.defaultSerialType,
|
[ Schema.column "id" Schema.defaultSerialType,
|
||||||
Schema.column "name" Schema.TStr,
|
Schema.column "name" Schema.TStr,
|
||||||
Schema.column "emails" textArrayType,
|
Schema.column "emails" textArrayType,
|
||||||
Schema.column "grid" nestedTextArrayType
|
Schema.column "grid" nestedIntArrayType,
|
||||||
|
Schema.column "jsons" jsonArrayType
|
||||||
],
|
],
|
||||||
Schema.tablePrimaryKey = ["id"]
|
Schema.tablePrimaryKey = ["id"]
|
||||||
}
|
}
|
||||||
@ -123,7 +150,8 @@ singleArrayTests = do
|
|||||||
{
|
{
|
||||||
name: "Ash",
|
name: "Ash",
|
||||||
emails: "{ash@ash.com, ash123@ash.com}",
|
emails: "{ash@ash.com, ash123@ash.com}",
|
||||||
grid: "{}"
|
grid: "{}",
|
||||||
|
jsons: "{}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
) {
|
) {
|
||||||
@ -138,7 +166,7 @@ singleArrayTests = do
|
|||||||
|
|
||||||
shouldReturnYaml testEnvironment actual expected
|
shouldReturnYaml testEnvironment actual expected
|
||||||
|
|
||||||
it "Using native GraphQL array syntax" \testEnvironment -> do
|
it "Text array using native GraphQL array syntax" \testEnvironment -> do
|
||||||
let expected :: Value
|
let expected :: Value
|
||||||
expected =
|
expected =
|
||||||
[interpolateYaml|
|
[interpolateYaml|
|
||||||
@ -161,7 +189,8 @@ singleArrayTests = do
|
|||||||
{
|
{
|
||||||
name: "Ash",
|
name: "Ash",
|
||||||
emails: ["ash@ash.com", "ash123@ash.com"],
|
emails: ["ash@ash.com", "ash123@ash.com"],
|
||||||
grid: []
|
grid: [],
|
||||||
|
jsons: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
) {
|
) {
|
||||||
@ -176,6 +205,90 @@ singleArrayTests = do
|
|||||||
|
|
||||||
shouldReturnYaml testEnvironment actual expected
|
shouldReturnYaml testEnvironment actual expected
|
||||||
|
|
||||||
|
jsonArrayTests :: SpecWith TestEnvironment
|
||||||
|
jsonArrayTests = do
|
||||||
|
describe "saves JSON arrays" $ do
|
||||||
|
it "JSON array using native GraphQL array syntax" \testEnvironment -> do
|
||||||
|
let expected :: Value
|
||||||
|
expected =
|
||||||
|
[interpolateYaml|
|
||||||
|
data:
|
||||||
|
insert_hasura_author:
|
||||||
|
affected_rows: 1
|
||||||
|
returning:
|
||||||
|
- name: "Bruce"
|
||||||
|
jsons: [{ name: "Mr Horse", age: 100}, { name: "Mr Dog", age: 1}]
|
||||||
|
|]
|
||||||
|
|
||||||
|
actual :: IO Value
|
||||||
|
actual =
|
||||||
|
postGraphql
|
||||||
|
testEnvironment
|
||||||
|
[graphql|
|
||||||
|
mutation {
|
||||||
|
insert_hasura_author (
|
||||||
|
objects: [
|
||||||
|
{
|
||||||
|
name: "Bruce",
|
||||||
|
emails: ["something@something.com"]
|
||||||
|
grid: [],
|
||||||
|
jsons: ["{ \"name\": \"Mr Horse\", \"age\": 100}", "{\"name\":\"Mr Dog\", \"age\": 1}"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
) {
|
||||||
|
affected_rows
|
||||||
|
returning {
|
||||||
|
name
|
||||||
|
jsons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
shouldReturnYaml testEnvironment actual expected
|
||||||
|
|
||||||
|
it "JSON array using native GraphQL array syntax and variable" \testEnvironment -> do
|
||||||
|
let expected :: Value
|
||||||
|
expected =
|
||||||
|
[interpolateYaml|
|
||||||
|
data:
|
||||||
|
insert_hasura_author:
|
||||||
|
affected_rows: 1
|
||||||
|
returning:
|
||||||
|
- name: "Bruce"
|
||||||
|
jsons: [{ name: "Mr Horse", age: 100}, "horses"]
|
||||||
|
|]
|
||||||
|
|
||||||
|
actual :: IO Value
|
||||||
|
actual =
|
||||||
|
postGraphqlWithVariables
|
||||||
|
testEnvironment
|
||||||
|
[graphql|
|
||||||
|
mutation json_variables_test($jsonArray: [json]) {
|
||||||
|
insert_hasura_author (
|
||||||
|
objects: [
|
||||||
|
{
|
||||||
|
name: "Bruce",
|
||||||
|
emails: ["something2@something2.com"],
|
||||||
|
grid: [],
|
||||||
|
jsons: $jsonArray
|
||||||
|
}
|
||||||
|
]
|
||||||
|
) {
|
||||||
|
affected_rows
|
||||||
|
returning {
|
||||||
|
name
|
||||||
|
jsons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
[yaml|
|
||||||
|
jsonArray: [{ name: "Mr Horse", age: 100 }, "horses"]
|
||||||
|
|]
|
||||||
|
|
||||||
|
shouldReturnYaml testEnvironment actual expected
|
||||||
|
|
||||||
describe "Filters with contains" $ do
|
describe "Filters with contains" $ do
|
||||||
it "finds values using _contains" \testEnvironment -> do
|
it "finds values using _contains" \testEnvironment -> do
|
||||||
void
|
void
|
||||||
@ -188,7 +301,8 @@ singleArrayTests = do
|
|||||||
{
|
{
|
||||||
name: "contains",
|
name: "contains",
|
||||||
emails: ["horse@horse.com", "dog@dog.com"],
|
emails: ["horse@horse.com", "dog@dog.com"],
|
||||||
grid: []
|
grid: [],
|
||||||
|
jsons: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
) {
|
) {
|
||||||
@ -234,7 +348,8 @@ singleArrayTests = do
|
|||||||
{
|
{
|
||||||
name: "contained_in",
|
name: "contained_in",
|
||||||
emails: ["horse@horse2.com", "dog@dog2.com"],
|
emails: ["horse@horse2.com", "dog@dog2.com"],
|
||||||
grid: []
|
grid: [],
|
||||||
|
jsons: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
) {
|
) {
|
||||||
@ -285,8 +400,8 @@ nestedArrayTests = do
|
|||||||
affected_rows: 1
|
affected_rows: 1
|
||||||
returning:
|
returning:
|
||||||
- name: "Ash"
|
- name: "Ash"
|
||||||
grid: [["one", "two", "three"],
|
grid: [[1,2,3],
|
||||||
["four", "five", "six"]]
|
[4,5,6]]
|
||||||
|]
|
|]
|
||||||
|
|
||||||
actual :: IO Value
|
actual :: IO Value
|
||||||
@ -300,7 +415,8 @@ nestedArrayTests = do
|
|||||||
{
|
{
|
||||||
name: "Ash",
|
name: "Ash",
|
||||||
emails: "{}",
|
emails: "{}",
|
||||||
grid: "{{one,two,three},{four,five,six}}"
|
grid: "{{1,2,3},{4,5,6}}",
|
||||||
|
jsons: "{}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
) {
|
) {
|
||||||
|
@ -332,7 +332,27 @@ buildArrayLiteral ts =
|
|||||||
PGValLquery t -> TELit $ escape t
|
PGValLquery t -> TELit $ escape t
|
||||||
PGValLtxtquery t -> TELit $ escape t
|
PGValLtxtquery t -> TELit $ escape t
|
||||||
PGValUnknown t -> TELit $ escape t
|
PGValUnknown t -> TELit $ escape t
|
||||||
|
PGValJSON (PG.JSON j) -> case j of
|
||||||
|
-- this is delicate - we want to encode JSON
|
||||||
|
-- that is provided to HGE as raw JSON literals provided via variables,
|
||||||
|
-- and in stringified form as received when
|
||||||
|
-- inlined in a query. Therefore we need to check whether any string
|
||||||
|
-- receive is a genuine JSON string value, or a stringified rich value.
|
||||||
|
String s -> case decode (txtToLbs s) of
|
||||||
|
Just jv -> fromJson jv -- it was some actual JSON in disguise! encode it like usual
|
||||||
|
Nothing -> TELit $ escape (escape s) -- it's an actual JSON string, so add quotes again
|
||||||
|
_ -> fromJson j
|
||||||
|
PGValJSONB (PG.JSONB j) -> case j of
|
||||||
|
-- we do the same for JSONB as JSON
|
||||||
|
String s -> case decode (txtToLbs s) of
|
||||||
|
Just jv -> fromJsonb jv -- it was some actual JSON in disguise! encode it like usual
|
||||||
|
Nothing -> TELit $ escape (escape s) -- it's an actual JSON string, so add quotes again
|
||||||
|
_ -> fromJsonb j
|
||||||
other -> txtEncodedVal other
|
other -> txtEncodedVal other
|
||||||
|
|
||||||
|
fromJson = TELit . escape . bsToTxt . PE.encodingBytes . PE.json_ast
|
||||||
|
fromJsonb = TELit . escape . bsToTxt . PE.encodingBytes . PE.jsonb_ast
|
||||||
|
|
||||||
inner = \case
|
inner = \case
|
||||||
TENull -> "null"
|
TENull -> "null"
|
||||||
TELit t -> t
|
TELit t -> t
|
||||||
|
Loading…
Reference in New Issue
Block a user