It's been 4 months since the 1.0.0 release of pg_graphql.
Since then, we’ve pushed several features to improve the APIs that pg_graphql
produces.
In this article, we’ll walk through those features and show examples of each.
📢 These features are only available on projects with Postgres version 15.1.0.63
or higher. For help with upgrading, please review the migrating and upgrading projects guide.
View Support
Prior to v1.1
, pg_graphql
would only reflect standard tables. Since then, views, materialized views, and foreign tables are now also reflected in the GraphQL schema.
For example:
_10create view "ProjectOwner" as_10 select_10 acc.id,_10 acc.name_10 from_10 account as acc_10 join role as r on r.id = acc.role_id_10 where acc.role = 'project_owner';
Since all entities exposed by pg_graphql
require primary keys, we must define that constraint for the view. We do that using a comment directive:
_10comment on view "ProjectOwner"_10 is '@graphql({"primary_key_columns": ["id"]})';
Which yields the GraphQL type:
_10type ProjectOwner implements Node {_10 nodeId: ID!_10 id: UUID!_10 name: String_10}
With associated Edge
and Connection
types. That enables querying via:
_10{_10 projectOwnerCollection(first: 2) {_10 edges {_10 node {_10 nodeId_10 name_10 }_10 }_10 }_10}
Additionally, simple views automatically support mutation events like inserts and updates. You might use these to migrate underlying tables while maintaining backwards compatibility with previous API versions.
Filtering
Filtering in SQL is endlessly flexible. We’ve taken two incremental steps to bring more of that flexibility to the GraphQL interface.
is null
and is not null
Handling null
values can be tricky in both SQL and GraphQL. However, there are similarities we can take advantage of.
In pg_graphql
, every scalar data type has its own filter type, such as IntFilter
and StringFilter
.
Each of these filter types now includes an is
argument, which allows you to filter based on whether a value is null or not null.
You can do this by using {is: NULL}
for null
values and {is: NOT_NULL}
for non-null
values.
_10enum FilterIs {_10 NULL_10 NOT_NULL_10}_10_10type IntFilter {_10 ..._10 is: FilterIs_10}
For example:
_10{_10 blogCollection(filter: { name: {is: NULL}}) {_10 ..._10 }_10}
to return all blog
s where the name
is null
.
like
, ilike
, and startsWith
Text filtering options in pg_graphql
have historically been restricted to equality checks. The hesitation was due to concerns about exposing a default filter that is difficult to index. The combination of citext and PGroonga available on the platform solves those scalability risks and enabled us to expand the StringFilter
with options for like
ilike
and startsWith
.
_10input StringFilter {_10 eq: String_10 ..._10 startsWith: String_10 like: String_10 ilike: String_10}
Note that startsWith
filters should be preferred where appropriate because they can leverage simple B-Tree indexes to improve performance.
_11{_11 generalLedgerCollection(filter: { identifierCode: { startsWith: "BX1:" } }) {_11 edges {_11 node {_11 nodeId_11 identifierCode_11 amount_11 }_11 }_11 }_11}
GraphQL directives @skip
and @include
The GraphQL spec has evolved over time. Although the spec is clear, it is common for GraphQL servers to selectively omit some chunks of functionality. For example, some frameworks intentionally do not expose an introspection schema as a form of security through obscurity.
pg_graphql
aims to be unopinionated and adhere exactly to the spec. The @skip
and @include
directives are part of the GraphQL core specification and are now functional.
The @skip
directive in GraphQL is used to conditionally skip a field or fragment during query execution based on a Boolean variable. It can be used to make the query more efficient by reducing the amount of data retrieved from the server.
The @include
directive is the mirror of @skip
where a field or fragment is conditionally included depending on the value of a Boolean variable.
Here's an example of how the @skip
directive can be used in a GraphQL query:
_11query getBooks($includeDetails: Boolean!) {_11 booksCollection {_11 edges {_11 node {_11 id_11 title_11 description @skip(if: $includeDetails)_11 }_11 }_11 }_11}
User Defined Descriptions
Users can now use the comment directive system to assign descriptions to tables, views and columns.
_10create table public.book(_10 id int primary key,_10 title text not null_10);_10_10comment on table public.book_10is e'@graphql({"description": "a library book"})';_10_10comment on column public.book.title_10is e'@graphql({"description": "the title of the book"})';
GraphQL IDEs, such as GraphiQL render those descriptions, allowing developers to provide clearer API documentation.
Roadmap
The headline features we aim to launch in coming releases of pg_graphql
include:
- Support for user-defined functions: GitHub issue
- Support for nested inserts: GitHub issue
- An alternative approach to computed relationships based on SQL functions returning
SET OF
rather than comment directives (compatible with PostgREST)