Skip to content

Better domain type support #399

Open
@andrew-w-ross

Description

@andrew-w-ross

Describe the bug

Types for scalar domain types return type Opaque and for array domain types they just fail.

To Reproduce

Given the following schema:

create domain pos_int as int check (value > 0);
create domain non_empty_array as int[] check (array_length(value, 1) > 0);
create domain pos_array as pos_int[];

create table domain_test(
    id serial primary key,
    int_field int,
    array_field int[],
    pos_int pos_int,
    non_empty_array non_empty_array,
    pos_array pos_array
);

insert into domain_test(int_field, array_field, pos_int, non_empty_array, pos_array)
values (1, '{1,2,3}', 1, '{1,2,3}', '{1,2,3}');

Querying for the types on domain_test returns the following:

select graphql.resolve($$
query {
  __type(name: "domain_test") {
    fields {
      name
      type {
        name
        kind
        ofType {
          name
          kind
          ofType {
            name
            kind
          }
        }
      }
    }
  }
}
$$);
{
  "data": {
    "__type": {
      "fields": [
        {
          "name": "nodeId",
          "type": {
            "kind": "NON_NULL",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "ID",
              "ofType": null
            }
          }
        },
        {
          "name": "id",
          "type": {
            "kind": "NON_NULL",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "Int",
              "ofType": null
            }
          }
        },
        {
          "name": "int_field",
          "type": {
            "kind": "SCALAR",
            "name": "Int",
            "ofType": null
          }
        },
        {
          "name": "array_field",
          "type": {
            "kind": "LIST",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "Int",
              "ofType": null
            }
          }
        },
        {
          "name": "pos_int",
          "type": {
            "kind": "SCALAR",
            "name": "Opaque",
            "ofType": null
          }
        }
      ]
    }
  }
}

Querying the data will work for the fields on the Opaque types:

select graphql.resolve($$
query {
  domain_testCollection{
    edges {
        node {
            id
            int_field
            array_field
            pos_int
        }
    }
  }
}
$$);
{
  "data": {
    "domain_testCollection": {
      "edges": [
        {
          "node": {
            "id": 1,
            "pos_int": 1,
            "int_field": 1,
            "array_field": [
              1,
              2,
              3
            ]
          }
        }
      ]
    }
  }
}

And fails for fields with an array domain_type:

select graphql.resolve($$
query {
  domain_testCollection{
    edges {
        node {
            id
            non_empty_array
        }
    }
  }
}
$$);
{
  "data": null,
  "errors": [
    {
      "message": "Unknown field 'non_empty_array' on type 'domain_test'"
    }
  ]
}

You can attempt the above with pos_array and get a similar result.

Expected behavior

For fields with domain types to resolve to there domain type or at least the domain base type.

E.g.

select graphql.resolve($$
query {
  __type(name: "domain_test") {
    fields {
      name
      type {
        name
        kind
        ofType {
          name
          kind
          ofType {
            name
            kind
          }
        }
      }
    }
  }
}
$$);

Would return:

{
  "data": {
    "__type": {
      "fields": [
        {
          "name": "nodeId",
          "type": {
            "kind": "NON_NULL",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "ID",
              "ofType": null
            }
          }
        },
        {
          "name": "id",
          "type": {
            "kind": "NON_NULL",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "Int",
              "ofType": null
            }
          }
        },
        {
          "name": "int_field",
          "type": {
            "kind": "SCALAR",
            "name": "Int",
            "ofType": null
          }
        },
        {
          "name": "array_field",
          "type": {
            "kind": "LIST",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "Int",
              "ofType": null
            }
          }
        },
        {
          "name": "pos_int",
          "type": {
            "kind": "SCALAR",
            "name": "Int",
            "ofType": null
          }
        },
        {
          "name": "non_empty_array",
          "type": {
            "kind": "LIST",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "Int",
              "ofType": null
            }
          }
        },
        {
          "name": "pos_array",
          "type": {
            "kind": "LIST",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "Int",
              "ofType": null
            }
          }
        }
      ]
    }
  }
}

The behavior of the field itself on querying would be the same as it's base type.

Screenshots
N/A

Versions:

  • PostgreSQL: 15
  • pg_graphql commit ref: ec3f7d5

Additional context
I think I have a possible fix for this and I'l like to try opening a pr to fix this.

A simple solution would be to resolve the base type of the domain object itself.
To my understanding domain types always have to eventually resolve to a built in sql scalar or array type so this seems like a valid solution.
While this would technically be a breaking change Opaque isn't particularly useful so it could also hide behind a schema directive flag but that would be opt out. This is also a possible fix for #370.

Let me know if you agree and I'll submit a pr.

The complete fix would be to generate new types for domain types.
That is breaking change and some client might not care to know about anything but the base type. It'll have to be behind a schema directive flag that's opt in.
I won't be attempting this approach right away just spitballing a final solution.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions