#
# This source file is part of the EdgeDB open source project.
#
# Copyright 2019-present MagicStack Inc. and the EdgeDB authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


import os
import unittest  # NOQA

import edgedb

from edb.testbase import http as tb


class TestGraphQLMutation(tb.GraphQLTestCase):
    SCHEMA_DEFAULT = os.path.join(os.path.dirname(__file__), 'schemas',
                                  'graphql.esdl')

    SCHEMA_OTHER = os.path.join(os.path.dirname(__file__), 'schemas',
                                'graphql_other.esdl')

    SETUP = os.path.join(os.path.dirname(__file__), 'schemas',
                         'graphql_setup.edgeql')

    # GraphQL queries cannot run in a transaction
    TRANSACTION_ISOLATION = False

    def test_graphql_mutation_insert_scalars_01(self):
        data = {
            'p_bool': False,
            'p_str': 'New ScalarTest01',
            'p_datetime': '2019-05-01T01:02:35.196811+00:00',
            'p_local_datetime': '2019-05-01T01:02:35.196811',
            'p_local_date': '2019-05-01',
            'p_local_time': '01:02:35.196811',
            'p_duration': 'PT21H30M',
            'p_int16': 12345,
            'p_int32': 1234567890,
            # Some GraphQL implementations seem to have a limitation
            # of not being able to handle 64-bit integer literals
            # (GraphiQL is among them).
            'p_int64': 1234567890,
            'p_bigint': 123456789123456789123456789,
            'p_float32': 4.5,
            'p_float64': 4.5,
            'p_decimal':
                123456789123456789123456789.123456789123456789123456789,
        }

        validation_query = r"""
            query {
                ScalarTest(filter: {p_str: {eq: "New ScalarTest01"}}) {
                    p_bool
                    p_str
                    p_datetime
                    p_local_datetime
                    p_local_date
                    p_local_time
                    p_duration
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest {
                insert_ScalarTest(
                    data: [{
                        p_bool: false,
                        p_str: "New ScalarTest01",
                        p_datetime: "2019-05-01T01:02:35.196811+00:00",
                        p_local_datetime: "2019-05-01T01:02:35.196811",
                        p_local_date: "2019-05-01",
                        p_local_time: "01:02:35.196811",
                        p_duration: "21:30:00",
                        p_int16: 12345,
                        p_int32: 1234567890,
                        p_int64: 1234567890,
                        p_bigint: 123456789123456789123456789,
                        p_float32: 4.5,
                        p_float64: 4.5,
                        p_decimal:
                123456789123456789123456789.123456789123456789123456789,
                    }]
                ) {
                    p_bool
                    p_str
                    p_datetime
                    p_local_datetime
                    p_local_date
                    p_local_time
                    p_duration
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "insert_ScalarTest": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(filter: {p_str: {eq: "New ScalarTest01"}}) {
                    p_bool
                    p_str
                    p_datetime
                    p_local_datetime
                    p_local_date
                    p_local_time
                    p_duration
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "delete_ScalarTest": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": []
        })

    def test_graphql_mutation_insert_scalars_02(self):
        # This tests int64 insertion. Apparently as long as the number
        # is provided as a variable parameter in JSON, there's no
        # limit on the number of digits of an Int.
        data = {
            'p_str': 'New ScalarTest02',
            'p_int64': 1234567890123,
        }

        validation_query = r"""
            query {
                ScalarTest(filter: {p_str: {eq: "New ScalarTest02"}}) {
                    p_str
                    p_int64
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest($num: Int64!) {
                insert_ScalarTest(
                    data: [{
                        p_str: "New ScalarTest02",
                        p_int64: $num,
                    }]
                ) {
                    p_str
                    p_int64
                }
            }
        """, {
            "insert_ScalarTest": [data]
        }, variables={'num': data['p_int64']})

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(filter: {p_str: {eq: "New ScalarTest02"}}) {
                    p_str
                    p_int64
                }
            }
        """, {
            "delete_ScalarTest": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": []
        })

    def test_graphql_mutation_insert_scalars_03(self):
        # This tests custom scalar insertion.
        data = {
            'p_str': 'New ScalarTest03',
            'p_posint': 42,
        }

        validation_query = r"""
            query {
                ScalarTest(filter: {p_str: {eq: "New ScalarTest03"}}) {
                    p_str
                    p_posint
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest {
                insert_ScalarTest(
                    data: [{
                        p_str: "New ScalarTest03",
                        p_posint: 42,
                    }]
                ) {
                    p_str
                    p_posint
                }
            }
        """, {
            "insert_ScalarTest": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(filter: {p_str: {eq: "New ScalarTest03"}}) {
                    p_str
                    p_posint
                }
            }
        """, {
            "delete_ScalarTest": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": []
        })

    def test_graphql_mutation_insert_scalars_04(self):
        # This tests JSON insertion. JSON can only be inserted via a variable.
        data = {
            'p_str': 'New ScalarTest04',
            'p_json': {"foo": [1, None, "aardvark"]},
        }

        validation_query = r"""
            query {
                ScalarTest(filter: {p_str: {eq: "New ScalarTest04"}}) {
                    p_str
                    p_json
                }
            }
        """

        self.assert_graphql_query_result(
            r"""
                mutation insert_ScalarTest(
                    $p_str: String!,
                    $p_json: JSON
                ) {
                    insert_ScalarTest(
                        data: [{
                            p_str: $p_str,
                            p_json: $p_json,
                        }]
                    ) {
                        p_str
                        p_json
                    }
                }
            """, {
                "insert_ScalarTest": [data]
            },
            variables=data,
        )

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(
            r"""
                mutation delete_ScalarTest(
                    $p_json: JSON
                ) {
                    delete_ScalarTest(filter: {p_json: {eq: $p_json}}) {
                        p_str
                        p_json
                    }
                }
            """, {
                "delete_ScalarTest": [data]
            },
            variables=data,
        )

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": []
        })

    def test_graphql_mutation_insert_scalars_05(self):
        # This tests string escapes.
        data = {
            'p_str': 'New \"ScalarTest05\"\\',
        }

        validation_query = r"""
            query {
                ScalarTest(filter: {p_str: {eq: "New \"ScalarTest05\"\\"}}) {
                    p_str
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest {
                insert_ScalarTest(
                    data: [{
                        p_str: "New \"ScalarTest05\"\\",
                    }]
                ) {
                    p_str
                }
            }
        """, {
            "insert_ScalarTest": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(
                    filter: {p_str: {eq: "New \"ScalarTest05\"\\"}}
                ) {
                    p_str
                }
            }
        """, {
            "delete_ScalarTest": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": []
        })

    def test_graphql_mutation_insert_scalars_06(self):
        # This tests float vs. decimal literals.
        data = {
            'p_str': 'New ScalarTest06',
            'p_decimal':
                123456789123456789123456789.123456789123456789123456789,
            'p_decimal_str':
                '123456789123456789123456789.123456789123456789123456789',
        }

        validation_query = r"""
            query {
                ScalarTest(filter: {p_str: {eq: "New ScalarTest06"}}) {
                    p_str
                    p_decimal
                    p_decimal_str
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest {
                insert_ScalarTest(
                    data: [{
                        p_str: "New ScalarTest06",
                        p_decimal:
                    123456789123456789123456789.123456789123456789123456789,
                    }]
                ) {
                    p_str
                    p_decimal
                    p_decimal_str
                }
            }
        """, {
            "insert_ScalarTest": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(
                    filter: {p_str: {eq: "New ScalarTest06"}}
                ) {
                    p_str
                    p_decimal
                    p_decimal_str
                }
            }
        """, {
            "delete_ScalarTest": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": []
        })

    def test_graphql_mutation_insert_enum_01(self):
        # This tests enum values in insertion.
        data = {
            'select': 'New EnumTest01',
            'color': 'GREEN',
        }

        validation_query = r"""
            query {
                other__Foo(filter: {select: {eq: "New EnumTest01"}}) {
                    select
                    color
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        select: "New EnumTest01",
                        color: GREEN,
                    }]
                ) {
                    select
                    color
                }
            }
        """, {
            "insert_other__Foo": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "other__Foo": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {select: {eq: "New EnumTest01"}}
                ) {
                    select
                    color
                }
            }
        """, {
            "delete_other__Foo": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "other__Foo": []
        })

    def test_graphql_mutation_insert_enum_02(self):
        # This tests enum values in insertion, using variables.
        data = {
            'select': 'New EnumTest02',
            'color': 'RED',
        }

        validation_query = r"""
            query {
                other__Foo(filter: {select: {eq: "New EnumTest02"}}) {
                    select
                    color
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_other__Foo(
                $select: String!,
                $color: other__ColorEnum!
            ) {
                insert_other__Foo(
                    data: [{
                        select: $select,
                        color: $color,
                    }]
                ) {
                    select
                    color
                }
            }
        """, {
            "insert_other__Foo": [data]
        }, variables=data)

        self.assert_graphql_query_result(validation_query, {
            "other__Foo": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {select: {eq: "New EnumTest02"}}
                ) {
                    select
                    color
                }
            }
        """, {
            "delete_other__Foo": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "other__Foo": []
        })

    def test_graphql_mutation_insert_nested_01(self):
        # Test nested insert.
        data = {
            'name': 'New UserGroup01',
            'settings': [{
                'name': 'setting01',
                'value': 'aardvark01',
            }],
        }

        validation_query = r"""
            query {
                UserGroup(filter: {name: {eq: "New UserGroup01"}}) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_UserGroup {
                insert_UserGroup(
                    data: [{
                        name: "New UserGroup01",
                        settings: [{
                            data: {
                                name: "setting01",
                                value: "aardvark01"
                            }
                        }],
                    }]
                ) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """, {
            "insert_UserGroup": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "UserGroup": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_UserGroup {
                delete_UserGroup(filter: {name: {eq: "New UserGroup01"}}) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """, {
            "delete_UserGroup": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "UserGroup": []
        })

    def test_graphql_mutation_insert_nested_02(self):
        # Test insert with nested existing object.
        data = {
            'name': 'New UserGroup02',
            'settings': [{
                'name': 'setting02',
                'value': 'aardvark02'
            }],
        }

        validation_query = r"""
            query {
                UserGroup(filter: {name: {eq: "New UserGroup02"}}) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """

        setting = self.graphql_query(r"""
            mutation insert_Setting {
                insert_Setting(data: [{
                    name: "setting02",
                    value: "aardvark02"
                }]) {
                    id
                    name
                    value
                }
            }
        """)['insert_Setting'][0]

        self.assert_graphql_query_result(rf"""
            mutation insert_UserGroup {{
                insert_UserGroup(
                    data: [{{
                        name: "New UserGroup02",
                        settings: [{{
                            filter: {{
                                id: {{eq: "{setting['id']}"}}
                            }}
                        }}],
                    }}]
                ) {{
                    name
                    settings {{
                        name
                        value
                    }}
                }}
            }}
        """, {
            "insert_UserGroup": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "UserGroup": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_UserGroup {
                delete_UserGroup(filter: {name: {eq: "New UserGroup02"}}) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """, {
            "delete_UserGroup": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "UserGroup": []
        })

    def test_graphql_mutation_insert_nested_03(self):
        # Test insert with nested existing object.
        data = {
            'name': 'New UserGroup03',
            'settings': [{
                'name': 'setting031',
                'value': 'aardvark03',
            }, {
                'name': 'setting032',
                'value': 'other03',
            }, {
                'name': 'setting033',
                'value': 'special03',
            }],
        }

        validation_query = r"""
            query {
                UserGroup(filter: {name: {eq: "New UserGroup03"}}) {
                    name
                    settings(order: {name: {dir: ASC}}) {
                        name
                        value
                    }
                }
            }
        """

        settings = self.graphql_query(r"""
            mutation insert_Setting {
                insert_Setting(data: [{
                    name: "setting031",
                    value: "aardvark03"
                }, {
                    name: "setting032",
                    value: "other03"
                }]) {
                    id
                    name
                    value
                }
            }
        """)['insert_Setting']

        # nested results aren't fetching correctly
        self.assert_graphql_query_result(rf"""
            mutation insert_UserGroup {{
                insert_UserGroup(
                    data: [{{
                        name: "New UserGroup03",
                        settings: [{{
                            filter: {{
                                id: {{eq: "{settings[0]['id']}"}}
                            }}
                        }}, {{
                            data: {{
                                name: "setting033",
                                value: "special03",
                            }}
                        }}, {{
                            filter: {{
                                name: {{eq: "{settings[1]['name']}"}}
                            }}
                        }}],
                    }}]
                ) {{
                    name
                    settings(order: {{name: {{dir: ASC}}}}) {{
                        name
                        value
                    }}
                }}
            }}
        """, {
            "insert_UserGroup": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "UserGroup": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_UserGroup {
                delete_UserGroup(filter: {name: {eq: "New UserGroup03"}}) {
                    name
                    settings(order: {name: {dir: ASC}}) {
                        name
                        value
                    }
                }
            }
        """, {
            "delete_UserGroup": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "UserGroup": []
        })

    def test_graphql_mutation_insert_nested_04(self):
        # Test nested insert for a singular link.
        data = {
            "name": "New User04",
            "age": 99,
            "score": 99.99,
            "profile": {
                "name": "Alice profile",
                "value": "special"
            }
        }

        validation_query = r"""
            query {
                User(filter: {name: {eq: "New User04"}}) {
                    name
                    age
                    score
                    profile {
                        name
                        value
                    }
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_User {
                insert_User(
                    data: [{
                        name: "New User04",
                        active: false,
                        age: 99,
                        score: 99.99,
                        profile: {
                            filter: {
                                name: {eq: "Alice profile"}
                            },
                            first: 1
                        },
                    }]
                ) {
                    name
                    age
                    score
                    profile {
                        name
                        value
                    }
                }
            }
        """, {
            "insert_User": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_User {
                delete_User(filter: {name: {eq: "New User04"}}) {
                    name
                    age
                    score
                    profile {
                        name
                        value
                    }
                }
            }
        """, {
            "delete_User": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "User": []
        })

    def test_graphql_mutation_insert_nested_05(self):
        # Test nested insert for a singular link.
        profile = self.graphql_query(r"""
            query {
                Profile(filter: {
                    name: {eq: "Alice profile"}
                }) {
                    id
                    name
                    value
                }
            }
        """)['Profile'][0]

        data = {
            "name": "New User05",
            "age": 99,
            "score": 99.99,
            "profile": profile
        }

        validation_query = r"""
            query {
                User(filter: {name: {eq: "New User05"}}) {
                    name
                    age
                    score
                    profile {
                        id
                        name
                        value
                    }
                }
            }
        """

        self.assert_graphql_query_result(rf"""
            mutation insert_User {{
                insert_User(
                    data: [{{
                        name: "New User05",
                        active: false,
                        age: 99,
                        score: 99.99,
                        profile: {{
                            filter: {{
                                id: {{eq: "{profile['id']}"}}
                            }},
                            first: 1
                        }},
                    }}]
                ) {{
                    name
                    age
                    score
                    profile {{
                        id
                        name
                        value
                    }}
                }}
            }}
        """, {
            "insert_User": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_User {
                delete_User(filter: {name: {eq: "New User05"}}) {
                    name
                    age
                    score
                    profile {
                        id
                        name
                        value
                    }
                }
            }
        """, {
            "delete_User": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "User": []
        })

    def test_graphql_mutation_insert_nested_06(self):
        # Test delete based on nested field.
        data = {
            'name': 'New UserGroup06',
            'settings': [{
                'name': 'setting06',
                'value': 'aardvark06',
            }],
        }

        validation_query = r"""
            query {
                UserGroup(
                    filter: {settings: {name: {eq: "setting06"}}}
                ) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_UserGroup {
                insert_UserGroup(
                    data: [{
                        name: "New UserGroup06",
                        settings: [{
                            data: {
                                name: "setting06",
                                value: "aardvark06"
                            }
                        }],
                    }]
                ) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """, {
            "insert_UserGroup": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "UserGroup": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_UserGroup {
                delete_UserGroup(
                    filter: {settings: {name: {eq: "setting06"}}}
                ) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """, {
            "delete_UserGroup": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "UserGroup": []
        })

    def test_graphql_mutation_insert_nested_07(self):
        # Test insert with nested object filter.
        data = {
            "name": "New User07",
            "age": 33,
            "score": 33.33,
            "groups": [{
                'name': 'New UserGroup07',
                'settings': [{
                    'name': 'setting07',
                    'value': 'aardvark07',
                }],
            }]
        }

        validation_query = r"""
            query {
                User(
                    filter: {groups: {settings: {name: {eq: "setting07"}}}}
                ) {
                    name
                    age
                    score
                    groups {
                        name
                        settings {
                            name
                            value
                        }
                    }
                }
            }
        """

        # insert the user groups first
        self.assert_graphql_query_result(r"""
            mutation insert_UserGroup {
                insert_UserGroup(
                    data: [{
                        name: "New UserGroup07",
                        settings: [{
                            data: {
                                name: "setting07",
                                value: "aardvark07"
                            }
                        }],
                    }]
                ) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """, {
            "insert_UserGroup": [data['groups'][0]]
        })

        # insert the User
        self.assert_graphql_query_result(r"""
            mutation insert_User {
                insert_User(
                    data: [{
                        name: "New User07",
                        active: true,
                        age: 33,
                        score: 33.33,
                        groups: {
                            filter: {
                                settings: {name: {eq: "setting07"}}
                            },
                            first: 1
                        },
                    }]
                ) {
                    name
                    age
                    score
                    groups {
                        name
                        settings {
                            name
                            value
                        }
                    }
                }
            }
        """, {
            "insert_User": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_User {
                delete_User(
                    filter: {groups: {settings: {name: {eq: "setting07"}}}}
                ) {
                    name
                    age
                    score
                    groups {
                        name
                        settings {
                            name
                            value
                        }
                    }
                }
            }
        """, {
            "delete_User": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "User": []
        })

        # cleanup
        self.assert_graphql_query_result(r"""
            mutation delete_UserGroup {
                delete_UserGroup(
                    filter: {settings: {name: {eq: "setting07"}}}
                ) {
                    name
                    settings {
                        name
                        value
                    }
                }
            }
        """, {
            "delete_UserGroup": data['groups']
        })

    def test_graphql_mutation_insert_nested_08(self):
        # Issue #1243
        # Test nested insert.
        data = {
            'name': 'Strategy01',
            'games': [{
                'name': 'SomeGame01',
                'players': [{
                    'name': 'Alice'
                }]
            }],
        }

        validation_query = r"""
            query {
                Genre(filter: {name: {eq: "Strategy01"}}) {
                    name
                    games {
                        name
                        players {
                            name
                        }
                    }
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_genre {
                insert_Genre(data: [
                    {
                        name: "Strategy01",
                        games: [{
                            data: {
                                name: "SomeGame01",
                                players: [{
                                    filter: {name: {eq: "Alice"}}
                                }]
                            }
                        }]
                    }
                ]) {
                    name
                    games {
                        name
                        players {
                            name
                        }
                    }
                }
            }

        """, {
            "insert_Genre": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "Genre": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_Genre {
                delete_Genre(filter: {name: {eq: "Strategy01"}}) {
                    name
                    games {
                        name
                        players {
                            name
                        }
                    }
                }
            }
        """, {
            "delete_Genre": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "Genre": []
        })

        self.assert_graphql_query_result(r"""
            mutation delete_Game {
                delete_Game(filter: {name: {eq: "SomeGame01"}}) {
                    name
                    players {
                        name
                    }
                }
            }
        """, {
            "delete_Game": data['games']
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(r'''
            query {
                Game(filter: {name: {eq: "SomeGame01"}}) {
                    name
                    players {
                        name
                    }
                }
            }
        ''', {
            "Game": []
        })

    def test_graphql_mutation_insert_nested_09(self):
        # Issue #3470
        # Test nested insert of the same type.
        data = {
            'after': 'BaseFoo09',
            'color': 'GREEN',
            'foos': [{
                'after': 'NestedFoo090',
                'color': 'RED',
            }, {
                'after': 'NestedFoo091',
                'color': 'BLUE',
            }],
        }

        validation_query = r"""
            query {
                other__Foo(filter: {after: {eq: "BaseFoo09"}}) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        after: "BaseFoo09",
                        color: GREEN,
                        foos: [{
                            data: {
                                after: "NestedFoo090",
                                color: RED,
                            }
                        }, {
                            data: {
                                after: "NestedFoo091",
                                color: BLUE,
                            }
                        }]
                    }]
                ) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """, {
            "insert_other__Foo": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "other__Foo": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {after: {like: "%Foo09%"}},
                    order: {color: {dir: ASC}}
                ) {
                    after
                    color
                }
            }
        """, {
            "delete_other__Foo": [{
                'after': 'NestedFoo090',
                'color': 'RED',
            }, {
                'after': 'BaseFoo09',
                'color': 'GREEN',
            }, {
                'after': 'NestedFoo091',
                'color': 'BLUE',
            }]
        })

    def test_graphql_mutation_insert_nested_10(self):
        # Issue #3470
        # Test nested insert of the same type.
        data = {
            'after': 'BaseFoo10',
            'color': 'GREEN',
            'foos': [{
                'after': 'NestedFoo100',
                'color': 'RED',
            }, {
                'after': 'NestedFoo101',
                'color': 'BLUE',
            }],
        }

        validation_query = r"""
            query {
                other__Foo(filter: {after: {eq: "BaseFoo10"}}) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        after: "NestedFoo100",
                        color: RED,
                    }]
                ) {
                    after
                    color
                }
            }
        """, {
            "insert_other__Foo": [data['foos'][0]]
        })

        self.assert_graphql_query_result(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        after: "BaseFoo10",
                        color: GREEN,
                        foos: [{
                            filter: {
                                after: {eq: "NestedFoo100"},
                            }
                        }, {
                            data: {
                                after: "NestedFoo101",
                                color: BLUE,
                            }
                        }]
                    }]
                ) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """, {
            "insert_other__Foo": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "other__Foo": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {after: {like: "%Foo10%"}},
                    order: {color: {dir: ASC}}
                ) {
                    after
                    color
                }
            }
        """, {
            "delete_other__Foo": [{
                'after': 'NestedFoo100',
                'color': 'RED',
            }, {
                'after': 'BaseFoo10',
                'color': 'GREEN',
            }, {
                'after': 'NestedFoo101',
                'color': 'BLUE',
            }]
        })

    def test_graphql_mutation_insert_bad_01(self):
        with self.assertRaisesRegex(
                edgedb.QueryError,
                r"Cannot query field 'insert_SettingAlias'"):
            self.graphql_query(r"""
                mutation insert_SettingAlias {
                    insert_SettingAlias(
                        data: [{
                            name: "badsetting01",
                            value: "red"
                        }]
                    ) {
                        name
                        value
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_02(self):
        with self.assertRaisesRegex(
            edgedb.QueryError,
            r"Field 'data' is not defined by type 'NestedInsertNamedObject'"
        ):
            self.graphql_query(r"""
                mutation insert_User {
                    insert_User(
                        data: [{
                            name: "Bad User02",
                            active: true,
                            age: 33,
                            score: 33.33,
                            favorites: [{
                                data: {
                                    name: "badsetting02",
                                }
                            }],
                        }]
                    ) {
                        name
                        age
                        score
                        favorites {
                            name
                            value
                        }
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_03(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"objects provided for 'settings' are not distinct"
        ):
            self.graphql_query(r"""
                mutation insert_UserGroup {
                    insert_UserGroup(
                        data: [{
                            name: "Bad UserGroup03",
                            settings: [{
                                filter: {name: {like: "%"}}
                            }, {
                                filter: {name: {like: "perks"}}
                            }]
                        }]
                    ) {
                        name
                        settings {
                            name
                            value
                        }
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_04(self):
        with self.assertRaisesRegex(
            edgedb.CardinalityViolationError,
            r"more than one object provided for 'profile'"
        ):
            self.graphql_query(r"""
                mutation insert_User {
                    insert_User(
                        data: [{
                            name: "Bad User04",
                            active: true,
                            age: 33,
                            score: 33.33,
                            profile: {
                                filter: {name: {like: "%"}}
                            },
                        }]
                    ) {
                        name
                        age
                        score
                        profile {
                            name
                        }
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_05(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"settings violates exclusivity constraint"
        ):
            self.graphql_query(r"""
                mutation insert_UserGroup {
                    insert_UserGroup(
                        data: [{
                            name: "Bad UserGroup05",
                            settings: {
                                filter: {name: {like: "perks"}}
                            }
                        }]
                    ) {
                        name
                        settings {
                            name
                            value
                        }
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_06(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"Minimum allowed value for positive_int_t is 0"
        ):
            self.graphql_query(r"""
                mutation insert_ScalarTest {
                    insert_ScalarTest(
                        data: [{
                            p_posint: -42,
                        }]
                    ) {
                        p_posint
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_07(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"p_short_str must be no longer than 5 characters"
        ):
            self.graphql_query(r"""
                mutation insert_ScalarTest {
                    insert_ScalarTest(
                        data: [{
                            p_short_str: "too long",
                        }]
                    ) {
                        p_short_str
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_08(self):
        with self.assertRaisesRegex(
            edgedb.InvalidValueError,
            r"invalid input syntax for type String: '2023/05/07'"
        ):
            self.graphql_query(r"""
                mutation insert_ScalarTest {
                    insert_ScalarTest(
                        data: [{
                            p_local_date: "2023/05/07",
                        }]
                    ) {
                        p_local_date
                    }
                }
            """)

    def test_graphql_mutation_insert_bad_09(self):
        with self.assertRaisesRegex(
            edgedb.InvalidValueError,
            r'String/String field value out of range: "2023-05-77"'
        ):
            self.graphql_query(r"""
                mutation insert_ScalarTest {
                    insert_ScalarTest(
                        data: [{
                            p_local_date: "2023-05-77",
                        }]
                    ) {
                        p_local_date
                    }
                }
            """)

    def test_graphql_mutation_insert_multiple_01(self):
        # Issue #1566
        # Test multiple mutations.
        data_s = {
            'name': 'multisetting01',
            'value': 'yellow',
        }
        data_p = {
            'name': 'multiprofile01',
            'value': 'multirofile',
        }

        validation_query = r"""
            query {
                Setting(filter: {name: {eq: "multisetting01"}}) {
                    name
                    value
                }
                Profile(filter: {name: {eq: "multiprofile01"}}) {
                    name
                    value
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation multi_insert {
                insert_Setting(
                    data: [{
                        name: "multisetting01",
                        value: "yellow"
                    }]
                ) {
                    name
                    value
                }
                insert_Profile(
                    data: [{
                        name: "multiprofile01",
                        value: "multirofile"
                    }]
                ) {
                    name
                    value
                }
            }
        """, {
            "insert_Setting": [data_s],
            "insert_Profile": [data_p]
        })

        self.assert_graphql_query_result(validation_query, {
            "Setting": [data_s],
            "Profile": [data_p],
        })

        self.assert_graphql_query_result(r"""
            mutation multi_delete {
                delete_Setting(
                    filter: {
                        name: {eq: "multisetting01"}
                    }
                ) {
                    name
                    value
                }
                delete_Profile(
                    filter: {
                        name: {eq: "multiprofile01"}
                    }
                ) {
                    name
                    value
                }
            }
        """, {
            "delete_Setting": [data_s],
            "delete_Profile": [data_p]
        })

        self.assert_graphql_query_result(validation_query, {
            "Setting": [],
            "Profile": [],
        })

    def test_graphql_mutation_insert_default_01(self):
        # Test insert object with a required property with a default.
        data = {
            'name': 'New InactiveUser01',
            'age': 99,
            'active': False,
            'score': 0,
        }

        validation_query = r"""
            query {
                User(filter: {name: {eq: "New InactiveUser01"}}) {
                    name
                    age
                    active
                    score
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation insert_User {
                insert_User(
                    data: [{
                        name: "New InactiveUser01",
                        age: 99
                    }]
                ) {
                    name
                    age
                    active
                    score
                }
            }
        """, {
            "insert_User": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_User {
                delete_User(filter: {name: {eq: "New InactiveUser01"}}) {
                    name
                    age
                    active
                    score
                }
            }
        """, {
            "delete_User": [data]
        })

        # validate that the deletion worked
        self.assert_graphql_query_result(validation_query, {
            "User": []
        })

    def test_graphql_mutation_update_scalars_01(self):
        orig_data = {
            'p_bool': True,
            'p_str': 'Hello world',
            'p_datetime': '2018-05-07T20:01:22.306916+00:00',
            'p_local_datetime': '2018-05-07T20:01:22.306916',
            'p_local_date': '2018-05-07',
            'p_local_time': '20:01:22.306916',
            'p_duration': 'PT20H',
            'p_int16': 12345,
            'p_int32': 1234567890,
            'p_int64': 1234567890123,
            'p_bigint': 123456789123456789123456789,
            'p_float32': 2.5,
            'p_float64': 2.5,
            'p_decimal':
                123456789123456789123456789.123456789123456789123456789,
        }
        data = {
            'p_bool': False,
            'p_str': 'Update ScalarTest01',
            'p_datetime': '2019-05-01T01:02:35.196811+00:00',
            'p_local_datetime': '2019-05-01T01:02:35.196811',
            'p_local_date': '2019-05-01',
            'p_local_time': '01:02:35.196811',
            'p_duration': 'PT21H30M',
            'p_int16': 4321,
            'p_int32': 876543210,
            # Some GraphQL implementations seem to have a limitation
            # of not being able to handle 64-bit integer literals
            # (GraphiQL is among them).
            'p_int64': 876543210,
            'p_bigint': 333333333333333333333333333,
            'p_float32': 4.5,
            'p_float64': 4.5,
            'p_decimal':
                444444444444444444444444444.222222222222222222222222222,
        }

        validation_query = rf"""
            query {{
                ScalarTest(
                    filter: {{
                        or: [{{
                            p_str: {{eq: "{orig_data['p_str']}"}}
                        }}, {{
                            p_str: {{eq: "{data['p_str']}"}}
                        }}]
                    }}
                ) {{
                    p_bool
                    p_str
                    p_datetime
                    p_local_datetime
                    p_local_date
                    p_local_time
                    p_duration
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }}
            }}
        """

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [orig_data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    data: {
                        p_bool: {set: false},
                        p_str: {set: "Update ScalarTest01"},
                        p_datetime: {set: "2019-05-01T01:02:35.196811+00:00"},
                        p_local_datetime: {set: "2019-05-01T01:02:35.196811"},
                        p_local_date: {set: "2019-05-01"},
                        p_local_time: {set: "01:02:35.196811"},
                        p_duration: {set: "PT21H30M"},
                        p_int16: {set: 4321},
                        p_int32: {set: 876543210},
                        # Some GraphQL implementations seem to have a
                        # limitation of not being able to handle 64-bit
                        # integer literals (GraphiQL is among them).
                        p_int64: {set: 876543210},
                        p_bigint: {set: 333333333333333333333333333},
                        p_float32: {set: 4.5},
                        p_float64: {set: 4.5},
                        p_decimal: {set:
                    444444444444444444444444444.222222222222222222222222222},
                    }
                ) {
                    p_bool
                    p_str
                    p_datetime
                    p_local_datetime
                    p_local_date
                    p_local_time
                    p_duration
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "update_ScalarTest": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest(
                $p_bool: Boolean,
                $p_str: String,
                $p_datetime: String,
                $p_local_datetime: String,
                $p_local_date: String,
                $p_local_time: String,
                $p_duration: String,
                $p_int16: Int,
                $p_int32: Int,
                $p_int64: Int64,
                $p_bigint: Bigint,
                $p_float32: Float,
                $p_float64: Float,
                $p_decimal: Decimal,
            ) {
                update_ScalarTest(
                    data: {
                        p_bool: {set: $p_bool},
                        p_str: {set: $p_str},
                        p_datetime: {set: $p_datetime},
                        p_local_datetime: {set: $p_local_datetime},
                        p_local_date: {set: $p_local_date},
                        p_local_time: {set: $p_local_time},
                        p_duration: {set: $p_duration},
                        p_int16: {set: $p_int16},
                        p_int32: {set: $p_int32},
                        p_int64: {set: $p_int64},
                        p_bigint: {set: $p_bigint},
                        p_float32: {set: $p_float32},
                        p_float64: {set: $p_float64},
                        p_decimal: {set: $p_decimal},
                    }
                ) {
                    p_bool
                    p_str
                    p_datetime
                    p_local_datetime
                    p_local_date
                    p_local_time
                    p_duration
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "update_ScalarTest": [orig_data]
        }, variables=orig_data)

        # validate that the final update worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [orig_data]
        })

    def test_graphql_mutation_update_scalars_02(self):
        orig_data = {
            'p_str': 'Hello world',
            'p_posint': 42,
            'p_short_str': 'hello',
        }
        data = {
            'p_str': 'Update ScalarTest02',
            'p_posint': 9999,
            'p_short_str': 'hi',
        }

        validation_query = rf"""
            query {{
                ScalarTest(
                    filter: {{
                        or: [{{
                            p_str: {{eq: "{orig_data['p_str']}"}}
                        }}, {{
                            p_str: {{eq: "{data['p_str']}"}}
                        }}]
                    }}
                ) {{
                    p_str
                    p_posint
                    p_short_str
                }}
            }}
        """

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [orig_data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    data: {
                        p_str: {set: "Update ScalarTest02"},
                        p_posint: {set: 9999},
                        p_short_str: {set: "hi"},
                    }
                ) {
                    p_str
                    p_posint
                    p_short_str
                }
            }
        """, {
            "update_ScalarTest": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest(
                $p_str: String,
                $p_posint: Int64,
                $p_short_str: String,
            ) {
                update_ScalarTest(
                    data: {
                        p_str: {set: $p_str},
                        p_posint: {set: $p_posint},
                        p_short_str: {set: $p_short_str},
                    }
                ) {
                    p_str
                    p_posint
                    p_short_str
                }
            }
        """, {
            "update_ScalarTest": [orig_data]
        }, variables=orig_data)

        # validate that the final update worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [orig_data]
        })

    def test_graphql_mutation_update_scalars_03(self):
        orig_data = {
            'p_str': 'Hello world',
            'p_json': {"foo": [1, None, "bar"]},
        }
        data = {
            'p_str': 'Update ScalarTest03',
            'p_json': {"bar": [None, 2, "aardvark"]},
        }

        validation_query = rf"""
            query {{
                ScalarTest(
                    filter: {{
                        or: [{{
                            p_str: {{eq: "{orig_data['p_str']}"}}
                        }}, {{
                            p_str: {{eq: "{data['p_str']}"}}
                        }}]
                    }}
                ) {{
                    p_str
                    p_json
                }}
            }}
        """

        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [orig_data]
        })

        # Test that basic and complex JSON values can be updated
        for json_val in [data['p_json'], data['p_json']['bar'],
                         True, 123, "hello world", None]:
            data['p_json'] = json_val
            self.assert_graphql_query_result(
                r"""
                    mutation update_ScalarTest(
                        $p_str: String!,
                        $p_json: JSON
                    ) {
                        update_ScalarTest(
                            data: {
                                p_str: {set: $p_str},
                                p_json: {set: $p_json},
                            }
                        ) {
                            p_str
                            p_json
                        }
                    }
                """, {
                    "update_ScalarTest": [data]
                },
                variables=data
            )

            self.assert_graphql_query_result(validation_query, {
                "ScalarTest": [data]
            })

        self.assert_graphql_query_result(
            r"""
                mutation update_ScalarTest(
                    $p_str: String,
                    $p_json: JSON,
                ) {
                    update_ScalarTest(
                        data: {
                            p_str: {set: $p_str},
                            p_json: {set: $p_json},
                        }
                    ) {
                        p_str
                        p_json
                    }
                }
            """, {
                "update_ScalarTest": [orig_data]
            },
            variables=orig_data
        )

        # validate that the final update worked
        self.assert_graphql_query_result(validation_query, {
            "ScalarTest": [orig_data]
        })

    def test_graphql_mutation_update_scalars_04(self):
        # This tests update ops for various numerical types.
        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest {
                insert_ScalarTest(
                    data: [{
                        p_str: "Update ScalarTest04",
                        p_int16: 0,
                        p_int32: 0,
                        p_int64: 0,
                        p_bigint: 0,
                        p_float32: 0,
                        p_float64: 0,
                        p_decimal: 0,
                    }]
                ) {
                    p_str
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "insert_ScalarTest": [{
                'p_str': 'Update ScalarTest04',
                'p_int16': 0,
                'p_int32': 0,
                'p_int64': 0,
                'p_bigint': 0,
                'p_float32': 0,
                'p_float64': 0,
                'p_decimal': 0,
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest04"}}
                    data: {
                        p_int16: {increment: 2},
                        p_int32: {increment: 2},
                        p_int64: {increment: 2},
                        p_bigint: {increment: 2},
                        p_float32: {increment: 1.5},
                        p_float64: {increment: 1.5},
                        p_decimal: {increment: 1.5},
                    }
                ) {
                    p_str
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': 'Update ScalarTest04',
                'p_int16': 2,
                'p_int32': 2,
                'p_int64': 2,
                'p_bigint': 2,
                'p_float32': 1.5,
                'p_float64': 1.5,
                'p_decimal': 1.5,
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest04"}}
                    data: {
                        p_int16: {decrement: 1},
                        p_int32: {decrement: 1},
                        p_int64: {decrement: 1},
                        p_bigint: {decrement: 1},
                        p_float32: {decrement: 0.4},
                        p_float64: {decrement: 0.4},
                        p_decimal: {decrement: 0.4},
                    }
                ) {
                    p_str
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': 'Update ScalarTest04',
                'p_int16': 1,
                'p_int32': 1,
                'p_int64': 1,
                'p_bigint': 1,
                'p_float32': 1.1,
                'p_float64': 1.1,
                'p_decimal': 1.1,
            }]
        })

        # clean up
        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest04"}}
                ) {
                    p_str
                    p_int16
                    p_int32
                    p_int64
                    p_bigint
                    p_float32
                    p_float64
                    p_decimal
                }
            }
        """, {
            "delete_ScalarTest": [{
                'p_str': 'Update ScalarTest04',
                'p_int16': 1,
                'p_int32': 1,
                'p_int64': 1,
                'p_bigint': 1,
                'p_float32': 1.1,
                'p_float64': 1.1,
                'p_decimal': 1.1,
            }]
        })

    def test_graphql_mutation_update_scalars_05(self):
        # This tests update ops for various numerical types.
        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest {
                insert_ScalarTest(
                    data: [{
                        p_str: "Update ScalarTest05",
                    }]
                ) {
                    p_str
                }
            }
        """, {
            "insert_ScalarTest": [{
                'p_str': 'Update ScalarTest05',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {like: "%Update ScalarTest05%"}}
                    data: {
                        p_str: {prepend: "--"},
                    }
                ) {
                    p_str
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': '--Update ScalarTest05',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {like: "%Update ScalarTest05%"}}
                    data: {
                        p_str: {append: "!!!"},
                    }
                ) {
                    p_str
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': '--Update ScalarTest05!!!',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {like: "%Update ScalarTest05%"}}
                    data: {
                        p_str: {slice: [1]},
                    }
                ) {
                    p_str
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': '-Update ScalarTest05!!!',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {like: "%Update ScalarTest05%"}}
                    data: {
                        p_str: {slice: [0, -1]},
                    }
                ) {
                    p_str
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': '-Update ScalarTest05!!',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {like: "%Update ScalarTest05%"}}
                    data: {
                        p_str: {slice: [1, -2]},
                    }
                ) {
                    p_str
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': 'Update ScalarTest05',
            }]
        })

        # clean up
        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(
                    filter: {p_str: {like: "%Update ScalarTest05%"}}
                ) {
                    p_str
                }
            }
        """, {
            "delete_ScalarTest": [{
                'p_str': 'Update ScalarTest05',
            }]
        })

    def test_graphql_mutation_update_scalars_06(self):
        # This tests update ops for various numerical types.
        self.assert_graphql_query_result(r"""
            mutation insert_ScalarTest {
                insert_ScalarTest(
                    data: [{
                        p_str: "Update ScalarTest06",
                        p_array_str: ["world"],
                        p_array_int64: [0],
                    }]
                ) {
                    p_str
                    p_array_str
                    p_array_int64
                }
            }
        """, {
            "insert_ScalarTest": [{
                'p_str': 'Update ScalarTest06',
                'p_array_str': ['world'],
                'p_array_int64': [0],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest06"}}
                    data: {
                        p_array_str: {prepend: ["Hello"]},
                        p_array_int64: {prepend: [1, 2]},
                    }
                ) {
                    p_str
                    p_array_str
                    p_array_int64
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': 'Update ScalarTest06',
                'p_array_str': ['Hello', 'world'],
                'p_array_int64': [1, 2, 0],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest06"}}
                    data: {
                        p_array_str: {append: ["!"]},
                        p_array_int64: {append: [3, 4]},
                    }
                ) {
                    p_str
                    p_array_str
                    p_array_int64
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': 'Update ScalarTest06',
                'p_array_str': ['Hello', 'world', '!'],
                'p_array_int64': [1, 2, 0, 3, 4],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest06"}}
                    data: {
                        p_array_str: {slice: [1]},
                        p_array_int64: {slice: [1]},
                    }
                ) {
                    p_str
                    p_array_str
                    p_array_int64
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': 'Update ScalarTest06',
                'p_array_str': ['world', '!'],
                'p_array_int64': [2, 0, 3, 4],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_ScalarTest {
                update_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest06"}}
                    data: {
                        p_array_str: {slice: [1, -2]},
                        p_array_int64: {slice: [1, -2]},
                    }
                ) {
                    p_str
                    p_array_str
                    p_array_int64
                }
            }
        """, {
            "update_ScalarTest": [{
                'p_str': 'Update ScalarTest06',
                'p_array_str': [],
                'p_array_int64': [0],
            }]
        })

        # clean up
        self.assert_graphql_query_result(r"""
            mutation delete_ScalarTest {
                delete_ScalarTest(
                    filter: {p_str: {eq: "Update ScalarTest06"}}
                ) {
                    p_str
                    p_array_str
                    p_array_int64
                }
            }
        """, {
            "delete_ScalarTest": [{
                'p_str': 'Update ScalarTest06',
                'p_array_str': [],
                'p_array_int64': [0],
            }]
        })

    def test_graphql_mutation_update_scalars_07(self):
        # This tests array of JSON mutations. JSON can only be
        # mutated via a variable.
        data = {
            'el0': {"foo": [1, None, "aardvark"]},
            'el1': False,
        }

        self.assert_graphql_query_result(
            r"""
                mutation insert_ScalarTest($el0: JSON!, $el1: JSON!) {
                    insert_ScalarTest(
                        data: [{
                            p_str: "Update ScalarTest07",
                            p_array_json: [$el0, $el1],
                        }]
                    ) {
                        p_str
                        p_array_json
                    }
                }
            """, {
                "insert_ScalarTest": [{
                    'p_str': 'Update ScalarTest07',
                    'p_array_json': [data['el0'], data['el1']],
                }]
            },
            variables=data,
        )

        self.assert_graphql_query_result(
            r"""
                mutation update_ScalarTest($el: JSON!) {
                    update_ScalarTest(
                        filter: {p_str: {eq: "Update ScalarTest07"}}
                        data: {
                            p_array_json: {prepend: [$el]},
                        }
                    ) {
                        p_str
                        p_array_json
                    }
                }
            """, {
                "update_ScalarTest": [{
                    'p_str': 'Update ScalarTest07',
                    'p_array_json': ["first", data['el0'], data['el1']],
                }]
            },
            variables={"el": "first"}
        )

        self.assert_graphql_query_result(
            r"""
                mutation update_ScalarTest($el: JSON!) {
                    update_ScalarTest(
                        filter: {p_str: {eq: "Update ScalarTest07"}}
                        data: {
                            p_array_json: {append: [$el]},
                        }
                    ) {
                        p_str
                        p_array_json
                    }
                }
            """, {
                "update_ScalarTest": [{
                    'p_str': 'Update ScalarTest07',
                    'p_array_json': ["first", data['el0'], data['el1'], 9999],
                }]
            },
            variables={"el": 9999}
        )

        self.assert_graphql_query_result(
            r"""
                mutation update_ScalarTest {
                    update_ScalarTest(
                        filter: {p_str: {eq: "Update ScalarTest07"}}
                        data: {
                            p_array_json: {slice: [1, 3]},
                        }
                    ) {
                        p_str
                        p_array_json
                    }
                }
            """, {
                "update_ScalarTest": [{
                    'p_str': 'Update ScalarTest07',
                    'p_array_json': [data['el0'], data['el1']],
                }]
            }
        )

        # clean up
        self.assert_graphql_query_result(
            r"""
                mutation delete_ScalarTest {
                    delete_ScalarTest(
                        filter: {p_str: {eq: "Update ScalarTest07"}}
                    ) {
                        p_str
                        p_array_json
                    }
                }
            """, {
                "delete_ScalarTest": [{
                    'p_str': 'Update ScalarTest07',
                    'p_array_json': [data['el0'], data['el1']],
                }]
            }
        )

    def test_graphql_mutation_update_enum_01(self):
        # This tests enum values in updates.

        self.assert_graphql_query_result(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        select: "Update EnumTest01",
                        color: BLUE
                    }]
                ) {
                    select
                    color
                }
            }
        """, {
            "insert_other__Foo": [{
                'select': 'Update EnumTest01',
                'color': 'BLUE',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_other__Foo {
                update_other__Foo(
                    filter: {select: {eq: "Update EnumTest01"}}
                    data: {
                        color: {set: RED}
                    }
                ) {
                    select
                    color
                }
            }
        """, {
            "update_other__Foo": [{
                'select': 'Update EnumTest01',
                'color': 'RED',
            }]
        })

        # clean up
        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {select: {eq: "Update EnumTest01"}}
                ) {
                    select
                    color
                }
            }
        """, {
            "delete_other__Foo": [{
                'select': 'Update EnumTest01',
                'color': 'RED',
            }]
        })

    def test_graphql_mutation_update_enum_02(self):
        # This tests enum values in updates using variables.

        self.assert_graphql_query_result(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        select: "Update EnumTest02",
                        color: BLUE
                    }]
                ) {
                    select
                    color
                }
            }
        """, {
            "insert_other__Foo": [{
                'select': 'Update EnumTest02',
                'color': 'BLUE',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_other__Foo (
                $color: other__ColorEnum!
            ) {
                update_other__Foo(
                    filter: {select: {eq: "Update EnumTest02"}}
                    data: {
                        color: {set: $color}
                    }
                ) {
                    select
                    color
                }
            }
        """, {
            "update_other__Foo": [{
                'select': 'Update EnumTest02',
                'color': 'RED',
            }]
        }, variables={"color": "RED"})

        # clean up
        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {select: {eq: "Update EnumTest02"}}
                ) {
                    select
                    color
                }
            }
        """, {
            "delete_other__Foo": [{
                'select': 'Update EnumTest02',
                'color': 'RED',
            }]
        })

    def test_graphql_mutation_update_link_01(self):
        orig_data = {
            'name': 'John',
            'groups': [{
                'name': 'basic'
            }],
        }
        data1 = {
            'name': 'John',
            'groups': [],
        }
        data2 = {
            'name': 'John',
            'groups': [{
                'name': 'basic'
            }, {
                'name': 'unused'
            }, {
                'name': 'upgraded'
            }],
        }

        validation_query = r"""
            query {
                User(
                    filter: {
                        name: {eq: "John"}
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """

        self.assert_graphql_query_result(validation_query, {
            "User": [orig_data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    data: {
                        groups: {
                            clear: true
                        }
                    },
                    filter: {
                        name: {eq: "John"}
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [data1]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data1]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    data: {
                        groups: {
                            set: [{
                                filter: {
                                    name: {like: "%"}
                                }
                            }]
                        }
                    },
                    filter: {
                        name: {eq: "John"}
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [data2]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data2]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    data: {
                        groups: {
                            set: [{
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }]
                        }
                    },
                    filter: {
                        name: {eq: "John"}
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [orig_data]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [orig_data]
        })

    def test_graphql_mutation_update_link_02(self):
        # test fancy filters for updates
        orig_data = {
            'name': 'John',
            'groups': [{
                'name': 'basic'
            }],
        }
        data2 = {
            'name': 'John',
            'groups': [{
                'name': 'basic'
            }, {
                'name': 'unused'
            }, {
                'name': 'upgraded'
            }],
        }

        validation_query = r"""
            query {
                User(
                    filter: {
                        name: {eq: "John"}
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """

        self.assert_graphql_query_result(validation_query, {
            "User": [orig_data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    data: {
                        groups: {
                            set: [{
                                filter: {
                                    settings: {name: {eq: "template"}}
                                }
                            }, {
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }]
                        }
                    },
                    filter: {
                        name: {eq: "John"}
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [data2]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data2]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    data: {
                        groups: {
                            set: [{
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }]
                        }
                    },
                    filter: {
                        name: {eq: "John"}
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [orig_data]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [orig_data]
        })

    def test_graphql_mutation_update_link_03(self):
        # test set ops for update of multi link
        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    filter: {
                        name: {eq: "Jane"}
                    },
                    data: {
                        groups: {
                            add: [{
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }]
                        }
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [{
                'name': 'Jane',
                'groups': [{
                    'name': 'basic'
                }, {
                    'name': 'upgraded'
                }],
            }]
        })

        # add an existing group
        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    filter: {
                        name: {eq: "Jane"}
                    },
                    data: {
                        groups: {
                            add: [{
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }]
                        }
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [{
                'name': 'Jane',
                'groups': [{
                    'name': 'basic'
                }, {
                    'name': 'upgraded'
                }],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    filter: {
                        name: {eq: "Jane"}
                    },
                    data: {
                        groups: {
                            remove: [{
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }]
                        }
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [{
                'name': 'Jane',
                'groups': [{
                    'name': 'upgraded'
                }],
            }]
        })

    def test_graphql_mutation_update_link_04(self):
        # test set ops for update of multi link with singleton values
        # (omitting the wrapping [...])
        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    filter: {
                        name: {eq: "Jane"}
                    },
                    data: {
                        groups: {
                            add: {
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }
                        }
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [{
                'name': 'Jane',
                'groups': [{
                    'name': 'basic'
                }, {
                    'name': 'upgraded'
                }],
            }]
        })

        # add an existing group
        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    filter: {
                        name: {eq: "Jane"}
                    },
                    data: {
                        groups: {
                            add: {
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }
                        }
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [{
                'name': 'Jane',
                'groups': [{
                    'name': 'basic'
                }, {
                    'name': 'upgraded'
                }],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    filter: {
                        name: {eq: "Jane"}
                    },
                    data: {
                        groups: {
                            remove: {
                                filter: {
                                    name: {eq: "basic"}
                                }
                            }
                        }
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [{
                'name': 'Jane',
                'groups': [{
                    'name': 'upgraded'
                }],
            }]
        })

        # set a specific group
        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    filter: {
                        name: {eq: "Jane"}
                    },
                    data: {
                        groups: {
                            set: {
                                filter: {
                                    name: {eq: "unused"}
                                }
                            }
                        }
                    }
                ) {
                    name
                    groups(order: {name: {dir: ASC}}) {
                        name
                    }
                }
            }
        """, {
            "update_User": [{
                'name': 'Jane',
                'groups': [{
                    'name': 'unused'
                }],
            }]
        })

    def test_graphql_mutation_update_link_05(self):
        # updating a single link
        orig_data = {
            'name': 'Alice',
            'profile': {
                'name': 'Alice profile'
            },
        }
        data1 = {
            'name': 'Alice',
            'profile': None,
        }

        validation_query = r"""
            query {
                User(
                    filter: {
                        name: {eq: "Alice"}
                    }
                ) {
                    name
                    profile {
                        name
                    }
                }
            }
        """

        self.assert_graphql_query_result(validation_query, {
            "User": [orig_data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    data: {
                        profile: {
                            clear: true
                        }
                    },
                    filter: {
                        name: {eq: "Alice"}
                    }
                ) {
                    name
                    profile {
                        name
                    }
                }
            }
        """, {
            "update_User": [data1]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [data1]
        })

        self.assert_graphql_query_result(r"""
            mutation update_User {
                update_User(
                    data: {
                        profile: {
                            set: {
                                filter: {
                                    name: {eq: "Alice profile"}
                                }
                            }
                        }
                    },
                    filter: {
                        name: {eq: "Alice"}
                    }
                ) {
                    name
                    profile {
                        name
                    }
                }
            }
        """, {
            "update_User": [orig_data]
        })

        self.assert_graphql_query_result(validation_query, {
            "User": [orig_data]
        })

    def test_graphql_mutation_update_link_06(self):
        # updating a single link targeting a type union
        orig_data = {
            'name': 'combo 0',
            'data': None,
        }
        data1 = {
            'name': 'combo 0',
            'data': {
                "__typename": "Setting_Type",
                "name": "perks",
            },
        }
        data2 = {
            'name': 'combo 0',
            'data': {
                "__typename": "Profile_Type",
                "name": "Bob profile",
            },
        }

        validation_query = r"""
            query {
                Combo(
                    filter: {name: {eq: "combo 0"}}
                ) {
                    name
                    data {
                        __typename
                        name
                    }
                }
            }
        """

        self.assert_graphql_query_result(validation_query, {
            "Combo": [orig_data]
        })

        self.assert_graphql_query_result(r"""
            mutation update_Combo {
                update_Combo(
                    data: {
                        data: {
                            set: {
                                filter: {name: {eq: "perks"}}
                            }
                        }
                    },
                    filter: {
                        name: {eq: "combo 0"}
                    }
                ) {
                    name
                    data {
                        __typename
                        name
                    }
                }
            }
        """, {
            "update_Combo": [data1]
        })

        self.assert_graphql_query_result(validation_query, {
            "Combo": [data1]
        })

        self.assert_graphql_query_result(r"""
            mutation update_Combo {
                update_Combo(
                    data: {
                        data: {
                            set: {
                                filter: {name: {eq: "Bob profile"}}
                            }
                        }
                    },
                    filter: {
                        name: {eq: "combo 0"}
                    }
                ) {
                    name
                    data {
                        __typename
                        name
                    }
                }
            }
        """, {
            "update_Combo": [data2]
        })

        self.assert_graphql_query_result(validation_query, {
            "Combo": [data2]
        })

        self.assert_graphql_query_result(r"""
            mutation update_Combo {
                update_Combo(
                    data: {
                        data: {
                            clear: true
                        }
                    },
                    filter: {
                        name: {eq: "combo 0"}
                    }
                ) {
                    name
                    data {
                        __typename
                        name
                    }
                }
            }
        """, {
            "update_Combo": [orig_data]
        })

        self.assert_graphql_query_result(validation_query, {
            "Combo": [orig_data]
        })

    def test_graphql_mutation_update_bad_01(self):
        with self.assertRaisesRegex(
                edgedb.QueryError,
                r"Cannot query field 'update_SettingAlias'"):
            self.graphql_query(r"""
                mutation update_SettingAlias {
                    update_SettingAlias(
                        filter: {name: {eq: "template"}}
                        data: {
                            value: {set: "red"},
                        }
                    ) {
                        name
                        value
                    }
                }
            """)

    def test_graphql_mutation_update_bad_02(self):
        with self.assertRaisesRegex(
                edgedb.QueryError,
                r"No update operation was specified"):
            self.graphql_query(r"""
                mutation update_User {
                    update_User(
                        data: {
                            groups: {
                            }
                        }
                    ) {
                        name
                        groups {
                            name
                        }
                    }
                }
            """)

    def test_graphql_mutation_update_bad_03(self):
        with self.assertRaisesRegex(
                edgedb.QueryError,
                r"Too many update operations were specified"):
            self.graphql_query(r"""
                mutation update_User {
                    update_User(
                        data: {
                            groups: {
                                set: {
                                    filter: {
                                        name: {like: "%"}
                                    }
                                },
                                clear: true
                            }
                        }
                    ) {
                        name
                        groups {
                            name
                        }
                    }
                }
            """)

    def test_graphql_mutation_update_bad_04(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"objects provided for 'settings' are not distinct"
        ):
            self.graphql_query(r"""
                mutation update_UserGroup {
                    update_UserGroup(
                        filter: {
                            name: {eq: "basic"}
                        },
                        data: {
                            settings: {
                                set: [{
                                    filter: {name: {like: "%"}}
                                }, {
                                    filter: {name: {like: "perks"}}
                                }]
                            }
                        }
                    ) {
                        name
                        settings {
                            name
                            value
                        }
                    }
                }
            """)

    def test_graphql_mutation_update_bad_05(self):
        with self.assertRaisesRegex(
            edgedb.CardinalityViolationError,
            r"more than one object provided for 'profile'"
        ):
            self.graphql_query(r"""
                mutation update_User {
                    update_User(
                        filter: {name: {eq: "Alice"}},
                        data: {
                            profile: {
                                set: {
                                    filter: {name: {like: "%"}}
                                }
                            }
                        }
                    ) {
                        name
                        age
                        score
                        profile {
                            name
                        }
                    }
                }
            """)

    def test_graphql_mutation_update_bad_06(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"settings violates exclusivity constraint"
        ):
            self.graphql_query(r"""
                mutation update_UserGroup {
                    update_UserGroup(
                        filter: {name: {eq: "unused"}},
                        data: {
                            settings: {
                                set : {filter: {name: {like: "perks"}}}
                            }
                        }
                    ) {
                        name
                        settings {
                            name
                            value
                        }
                    }
                }
            """)

    def test_graphql_mutation_update_bad_07(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"Minimum allowed value for positive_int_t is 0"
        ):
            self.graphql_query(r"""
                mutation update_ScalarTest {
                    update_ScalarTest(
                        filter: {p_str: {eq: "Hello world"}}
                        data: {
                            p_posint: {set: -42},
                        }
                    ) {
                        p_posint
                    }
                }
            """)

    def test_graphql_mutation_update_bad_08(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"p_short_str must be no longer than 5 characters"
        ):
            self.graphql_query(r"""
                mutation update_ScalarTest {
                    update_ScalarTest(
                        filter: {p_str: {eq: "Hello world"}}
                        data: {
                            p_short_str: {set: "too long"},
                        }
                    ) {
                        p_short_str
                    }
                }
            """)

    def test_graphql_mutation_update_bad_09(self):
        with self.assertRaisesRegex(
            edgedb.NumericOutOfRangeError,
            r"Int out of range"
        ):
            self.graphql_query(r"""
                mutation update_ScalarTest {
                    update_ScalarTest(
                        filter: {p_str: {eq: "Hello world"}}
                        data: {
                            p_int32: {increment: 1234567890},
                        }
                    ) {
                        p_int32
                    }
                }
            """)

    def test_graphql_mutation_update_bad_10(self):
        with self.assertRaisesRegex(
            edgedb.AccessPolicyError,
            r"access policy violation on update of ErrorTest"
        ):
            self.graphql_query(r"""
                mutation update_ErrorTest {
                    update_ErrorTest(
                        data: {val: {set: -5}}
                    ) {
                        text
                    }
                }
        """)

    def test_graphql_mutation_update_bad_11(self):
        # We expect a rewrite rule to cause a division by 0 error.
        with self.assertRaisesRegex(
            edgedb.DivisionByZeroError,
            r"division by zero"
        ):
            self.graphql_query(r"""
                mutation update_ErrorTest {
                    update_ErrorTest(
                        data: {val: {set: 15}}
                    ) {
                        text
                    }
                }
        """)

    def test_graphql_mutation_update_bad_12(self):
        # We expect a rewrite rule to convert "" to empty set.
        with self.assertRaisesRegex(
            edgedb.MissingRequiredError,
            r"missing value for required property 'text' of object "
            r"type 'ErrorTest'"
        ):
            self.graphql_query(r"""
                mutation update_ErrorTest {
                    update_ErrorTest(
                        data: {text: {set: ""}}
                    ) {
                        text
                    }
                }
        """)

    def test_graphql_mutation_update_bad_13(self):
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"ErrorTest cannot have val equal to the length of text field"
        ):
            self.graphql_query(r"""
                mutation update_ErrorTest {
                    update_ErrorTest(
                        data: {val: {set: 7}}
                    ) {
                        text
                    }
                }
        """)

    def test_graphql_mutation_update_multiple_01(self):
        # Issue #1566
        # Test multiple mutations.
        validation_query = r"""
            query {
                Setting(filter: {name: {eq: "perks"}}) {
                    name
                    value
                }
                Profile(filter: {name: {eq: "Alice profile"}}) {
                    name
                    value
                }
            }
        """

        self.assert_graphql_query_result(r"""
            mutation multi_update {
                update_Setting(
                    filter: {name: {eq: "perks"}},
                    data: {
                        value: {set: "min"}
                    }
                ) {
                    name
                    value
                }
                update_Profile(
                    filter: {name: {eq: "Alice profile"}},
                    data: {
                        value: {set: "updated"}
                    }
                ) {
                    name
                    value
                }
            }
        """, {
            "update_Setting": [{
                'name': 'perks',
                'value': 'min',
            }],
            "update_Profile": [{
                'name': 'Alice profile',
                'value': 'updated',
            }]
        })

        self.assert_graphql_query_result(validation_query, {
            "Setting": [{
                'name': 'perks',
                'value': 'min',
            }],
            "Profile": [{
                'name': 'Alice profile',
                'value': 'updated',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation multi_update {
                update_Setting(
                    filter: {name: {eq: "perks"}},
                    data: {
                        value: {set: "full"}
                    }
                ) {
                    name
                    value
                }
                update_Profile(
                    filter: {name: {eq: "Alice profile"}},
                    data: {
                        value: {set: "special"}
                    }
                ) {
                    name
                    value
                }
            }
        """, {
            "update_Setting": [{
                'name': 'perks',
                'value': 'full',
            }],
            "update_Profile": [{
                'name': 'Alice profile',
                'value': 'special',
            }]
        })

    def test_graphql_mutation_update_multiple_02(self):
        # Issue #3470
        # Test nested update of the same type.
        data = {
            'after': 'BaseFoo02',
            'color': 'GREEN',
            'foos': [{
                'after': 'NestedFoo020',
                'color': 'RED',
            }, {
                'after': 'NestedFoo021',
                'color': 'BLUE',
            }],
        }

        validation_query = r"""
            query {
                other__Foo(filter: {after: {eq: "BaseFoo02"}}) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """

        self.graphql_query(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        after: "NestedFoo020",
                        color: RED
                    }, {
                        after: "BaseFoo02",
                        color: GREEN
                    }, {
                        after: "NestedFoo021",
                        color: BLUE
                    }]
                ) {
                    color
                }
            }
        """)

        self.assert_graphql_query_result(r"""
            mutation update_other__Foo {
                update_other__Foo(
                    filter: {after: {eq: "BaseFoo02"}},
                    data: {
                        foos: {
                            set: [{
                                filter: {
                                    after: {like: "NestedFoo02%"},
                                }
                            }]
                        }
                    }
                ) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """, {
            "update_other__Foo": [data]
        })

        self.assert_graphql_query_result(validation_query, {
            "other__Foo": [data]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {after: {like: "%Foo02%"}},
                    order: {color: {dir: ASC}}
                ) {
                    after
                    color
                }
            }
        """, {
            "delete_other__Foo": [{
                'after': 'NestedFoo020',
                'color': 'RED',
            }, {
                'after': 'BaseFoo02',
                'color': 'GREEN',
            }, {
                'after': 'NestedFoo021',
                'color': 'BLUE',
            }]
        })

    def test_graphql_mutation_update_multiple_03(self):
        # Issue #3470
        # Test nested update of the same type.
        self.graphql_query(r"""
            mutation insert_other__Foo {
                insert_other__Foo(
                    data: [{
                        after: "NestedFoo030",
                        color: RED
                    }, {
                        after: "BaseFoo03",
                        color: GREEN
                    }, {
                        after: "NestedFoo031",
                        color: BLUE
                    }]
                ) {
                    color
                }
            }
        """)

        self.assert_graphql_query_result(r"""
            mutation update_other__Foo {
                update_other__Foo(
                    filter: {after: {eq: "BaseFoo03"}},
                    data: {
                        foos: {
                            add: [{
                                filter: {
                                    after: {like: "NestedFoo03%"},
                                }
                            }]
                        }
                    }
                ) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """, {
            "update_other__Foo": [{
                'after': 'BaseFoo03',
                'color': 'GREEN',
                'foos': [{
                    'after': 'NestedFoo030',
                    'color': 'RED',
                }, {
                    'after': 'NestedFoo031',
                    'color': 'BLUE',
                }],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation update_other__Foo {
                update_other__Foo(
                    filter: {after: {eq: "BaseFoo03"}},
                    data: {
                        foos: {
                            remove: [{
                                filter: {
                                    after: {eq: "NestedFoo031"},
                                }
                            }]
                        }
                    }
                ) {
                    after
                    color
                    foos(order: {color: {dir: ASC}}) {
                        after
                        color
                    }
                }
            }
        """, {
            "update_other__Foo": [{
                'after': 'BaseFoo03',
                'color': 'GREEN',
                'foos': [{
                    'after': 'NestedFoo030',
                    'color': 'RED',
                }],
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_other__Foo {
                delete_other__Foo(
                    filter: {after: {like: "%Foo03%"}},
                    order: {color: {dir: ASC}}
                ) {
                    after
                    color
                }
            }
        """, {
            "delete_other__Foo": [{
                'after': 'NestedFoo030',
                'color': 'RED',
            }, {
                'after': 'BaseFoo03',
                'color': 'GREEN',
            }, {
                'after': 'NestedFoo031',
                'color': 'BLUE',
            }]
        })

    def test_graphql_mutation_delete_alias_01(self):
        self.assert_graphql_query_result(r"""
            mutation insert_Setting {
                insert_Setting(
                    data: [{
                        name: "delsetting01",
                        value: "red"
                    }]
                ) {
                    name
                    value
                }
            }
        """, {
            "insert_Setting": [{
                'name': 'delsetting01',
                'value': 'red',
            }]
        })

        self.assert_graphql_query_result(r"""
            mutation delete_SettingAlias {
                delete_SettingAlias(
                    filter: {
                        name: {eq: "delsetting01"}
                    }
                ) {
                    name
                    value
                }
            }
        """, {
            "delete_SettingAlias": [{
                'name': 'delsetting01',
                'value': 'red',
            }]
        })

        self.assert_graphql_query_result(r"""
            query get_SettingAlias {
                SettingAlias(
                    filter: {
                        name: {eq: "delsetting01"}
                    }
                ) {
                    name
                    value
                }
            }
        """, {
            "SettingAlias": []
        })

    def test_graphql_mutation_delete_bad_01(self):
        # We expext a rewrite rule to cause a division by 0 error.
        with self.assertRaisesRegex(
            edgedb.ConstraintViolationError,
            r"deletion of UserGroup .+is prohibited by link target policy"
        ):
            self.graphql_query(r"""
                mutation delete_UserGroup {
                    delete_UserGroup {
                        name
                    }
                }
        """)

    def test_graphql_mutation_bigint(self):
        self.assert_graphql_query_result(r"""
            mutation insert_BigIntTest {
                insert_BigIntTest(
                    data: [{value: 1e100}]
                ) {
                    value
                }
            }
        """, {
            "insert_BigIntTest": [{"value": 10**100}]
        })
