Skip to content

Configuration

Extra configuration options can be set on SQL entities using comment directives.

Comment Directives

Comment directives are snippets of configuration associated with SQL entities that alter how those entities behave.

The format of a comment directive is

1
@graphql(<JSON>)

Inflection

Inflection describes how SQL entities' names are transformed into GraphQL type and field names. By default, inflection is disabled and SQL names are literally interpolated such that

1
2
3
4
create table "BlogPost"(
    id int primary key,
    ...
);

results in GraphQL type names like

1
2
3
4
BlogPost
BlogPostEdge
BlogPostConnection
...

Since snake case is a common casing structure for SQL types, pg_graphql support basic inflection from snake_case to PascalCase for type names, and snake_case to camelCase for field names to match Javascript conventions.

The inflection directive can be applied at the schema level with:

1
comment on schema <schema_name> is e'@graphql({"inflect_names": true})';

for example

1
2
3
4
5
6
comment on schema public is e'@graphql({"inflect_names": true})';

create table blog_post(
    id int primary key,
    ...
);

similarly would generated the GraphQL type names

1
2
3
4
BlogPost
BlogPostEdge
BlogPostConnection
...

For more fine grained adjustments to reflected names, see renaming.

Max Rows

The default page size for collections is 30 entries. To adjust the number of entries on each page, set a max_rows directive on the relevant schema entity.

For example, to increase the max rows per page for each table in the public schema:

1
comment on schema public is e'@graphql({"max_rows": 100})';

totalCount

totalCount is an opt-in field that extends a table's Connection type. It provides a count of the rows that match the query's filters, and ignores pagination arguments.

1
2
3
4
5
6
7
type BlogPostConnection {
  edges: [BlogPostEdge!]!
  pageInfo: PageInfo!

  """The total number of records matching the `filter` criteria"""
  totalCount: Int! # this field
}

to enable totalCount for a table, use the directive

1
comment on table "BlogPost" is e'@graphql({"totalCount": {"enabled": true}})';
for example
1
2
3
4
5
create table "BlogPost"(
    id serial primary key,
    email varchar(255) not null
);
comment on table "BlogPost" is e'@graphql({"totalCount": {"enabled": true}})';

Renaming

Table's Type

Use the "name" JSON key to override a table's type name.

1
2
3
4
5
6
create table account(
    id serial primary key
);

comment on table public.account is
e'@graphql({"name": "AccountHolder"})';

results in:

1
2
3
type AccountHolder { # previously: "Account"
  id: Int!
}

Column's Field Name

Use the "name" JSON key to override a column's field name.

1
2
3
4
5
6
7
create table public."Account"(
    id serial primary key,
    email text
);

comment on column "Account".email is
e'@graphql({"name": "emailAddress"})';

results in:

1
2
3
4
5
type Account {
  nodeId: ID!
  id: Int!
  emailAddress: String! # previously "email"
}

Computed Field

Use the "name" JSON key to override a computed field's name.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
create table "Account"(
    id serial primary key,
    "firstName" varchar(255) not null,
    "lastName" varchar(255) not null
);

-- Extend with function
create function public."_fullName"(rec public."Account")
    returns text
    immutable
    strict
    language sql
as $$
    select format('%s %s', rec."firstName", rec."lastName")
$$;

comment on function public._full_name is
e'@graphql({"name": "displayName"})';

results in:

1
2
3
4
5
6
7
type Account {
  nodeId: ID!
  id: Int!
  firstName: String!
  lastName: String!
  displayName: String # previously "fullName"
}

Relationship's Field

Use the "local_name" and "foreign_name" JSON keys to override a a relationships inbound and outbound field names.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
create table "Account"(
    id serial primary key
);

create table "Post"(
    id serial primary key,
    "accountId" integer not null references "Account"(id),
    title text not null,
    body text
);

comment on constraint post_owner_id_fkey
  on "Post"
  is E'@graphql({"foreign_name": "author", "local_name": "posts"})';

results in:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
type Post {
  nodeId: ID!
  id: Int!
  accountId: Int!
  title: String!
  body: String!
  author: Account # was "account"
}

type Account {
  id: Int!
  posts( # was "postCollection"
    after: Cursor,
    before: Cursor,
    filter: PostFilter,
    first: Int,
    last: Int,
    orderBy: [PostOrderBy!]
  ): PostConnection
}

Description

Tables, Columns, and Functions accept a description directive to populate user defined descriptions in the GraphQL schema.

1
2
3
4
5
6
7
8
9
create table "Account"(
    id serial primary key
);

comment on table public.account
is e'@graphql({"description": "A User Account"})';

comment on column public.account.id
is e'@graphql({"description": "The primary key identifier"})';
1
2
3
4
5
6
"""A User Account"""
type Account implements Node {

  """The primary key identifier"""
  id: Int!
}

Enum Variant

If a variant of a Postgres enum does not conform to GraphQL naming conventions, introspection returns an error:

For example:

1
create type "Algorithm" as enum ('aead-ietf');

causes the error:

1
2
3
4
5
6
7
{
  "errors": [
    {
      "message": "Names must only contain [_a-zA-Z0-9] but \"aead-ietf\" does not.",
    }
  ]
}

To resolve this problem, rename the invalid SQL enum variant to a GraphQL compatible name:

1
alter type "Algorithm" rename value 'aead-ietf' to 'AEAD_IETF';

or, add a comment directive to remap the enum variant in the GraphQL API

1
comment on type "Algorithm" is '@graphql({"mappings": {"aead-ietf": "AEAD_IETF"}})';

Which both result in the GraphQL enum:

1
2
3
enum Algorithm {
  AEAD_IETF
}