Skip to content

Commit

Permalink
update docs for 0_1_2
Browse files Browse the repository at this point in the history
  • Loading branch information
olirice committed Mar 16, 2022
1 parent 4c34936 commit 79e0a60
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 82 deletions.
24 changes: 10 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,17 @@

---

Query your existing PostgreSQL database with GraphQL
`pg_graphql` adds GraphQL support to your PostgreSQL database.

`pg_graphql` inspects your PostgreSQL schema and reflects a GraphQL schema with resolvers.

- [x] __Performant__: [+2k requests/second](https://supabase.github.io/pg_graphql/performance/)
- [x] __Always up-to-date__: Reflected from the SQL schema
- [x] __Pagination__: Relay compliant
- [x] __Serverless__: Runs in your database with no *additional* server required
- [x] __Open Source__: Apache License 2.0

__pg_graphql is pre-alpha software under active development__
- [x] __Performant__
- [x] __Consistent__
- [x] __Serverless__
- [x] __Open Source__

### Overview
`pg_graphql` provides an SQL schema -> GraphQL schema reflection engine and an associated GraphQL query -> SQL query transpiler.
`pg_graphql` reflects a GraphQL schema from the existing SQL schema.

The extension keeps schema generation, query parsing, and resolvers all neatly contained on your database. This enables any programming language that can connect to PostgreSQL to query the database via GraphQL with no additional servers, processes, or libraries.
The extension keeps schema translation and query resolution neatly contained on your database server. This enables any programming language that can connect to PostgreSQL to query the database via GraphQL with no additional servers, processes, or libraries.


### TL;DR
Expand All @@ -41,7 +36,6 @@ The SQL schema
create table account(
id serial primary key,
email varchar(255) not null,
encrypted_password varchar(255) not null,
created_at timestamp not null,
updated_at timestamp not null
);
Expand All @@ -67,6 +61,8 @@ create table blog_post(
updated_at timestamp not null
);
```
Translates into a GraphQL schema exposing each table as a pageable collection with relationships defined by the foreign keys.
Translates into a GraphQL schema displayed below.

Each table receives an entrypoint in the top level `Query` type that is a pageable collection with relationships defined by its foreign keys. Tables similarly recieve entrypoints in the `Mutation` schema that enable bulk operations for insert, update, and delete.

![GraphiQL](./docs/assets/quickstart_graphiql.png)
10 changes: 5 additions & 5 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
The public API consists of a single function to resolve GraphQL queries. All other entities in the `graphql` schema are private.
The public facing API consists of a single SQL function that resolves GraphQL queries. All other entities in the `graphql` schema are private.

### graphql.resolve

##### description
Resolves a GraphQL query, returning JSONB.



##### signature
```sql
graphql.resolve(
Expand All @@ -26,17 +24,19 @@ graphql.resolve(
##### usage

```sql
-- Setup
-- Create the extension
graphqldb= create extension pg_graphql cascade;
CREATE EXTENSION

-- Create an example table
graphqldb= create table book(id int primary key, title text);
CREATE TABLE

-- Insert a record
graphqldb= insert into book(id, title) values (1, 'book 1');
INSERT 0 1

-- Example
-- Query the table via GraphQL
graphqldb= select graphql.resolve($$
query {
bookCollection {
Expand Down
5 changes: 0 additions & 5 deletions docs/assets/demo_schema.graphql
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
type Account {
id: Int!
email: String!
encryptedPassword: String!
createdAt: DateTime!
updatedAt: DateTime!
blogCollection(
Expand Down Expand Up @@ -49,14 +48,12 @@ type AccountEdge {
input AccountFilter {
id: IntFilter
email: StringFilter
encryptedPassword: StringFilter
createdAt: DateTimeFilter
updatedAt: DateTimeFilter
}

input AccountInsertInput {
email: String
encryptedPassword: String
createdAt: DateTime
updatedAt: DateTime
}
Expand All @@ -72,14 +69,12 @@ type AccountInsertResponse {
input AccountOrderBy {
id: OrderByDirection
email: OrderByDirection
encryptedPassword: OrderByDirection
createdAt: OrderByDirection
updatedAt: OrderByDirection
}

input AccountUpdateInput {
email: String
encryptedPassword: String
createdAt: DateTime
updatedAt: DateTime
}
Expand Down
1 change: 0 additions & 1 deletion docs/assets/demo_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ comment on schema public is '@graphql({"inflect_names": true})';
create table account(
id serial primary key,
email varchar(255) not null,
encrypted_password varchar(255) not null,
created_at timestamp not null,
updated_at timestamp not null
);
Expand Down
4 changes: 2 additions & 2 deletions docs/computed_fields.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## PostgreSQL Builtin
## PostgreSQL Builtin (Preferred)

PostgreSQL has a builtin feature for adding [generated columns](https://www.postgresql.org/docs/14/ddl-generated-columns.html) to tables. Generated columns are reflected identically to non-generated columns. This is the reccomended approach to adding computed fields when your computation meets the restrictions. The most significant restrictions of generated columns are:
PostgreSQL has a builtin method for adding [generated columns](https://www.postgresql.org/docs/14/ddl-generated-columns.html) to tables. Generated columns are reflected identically to non-generated columns. This is the reccomended approach to adding computed fields when your computation meets the restrictions. Namely:

- expression must be immutable
- expression may only reference the current row
Expand Down
28 changes: 5 additions & 23 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
## Table/Column Visibility
Table and column visibility in the GraphQL schema are controlled by standard PostgreSQL permissions. Revoking `SELECT` access from the user/role executing queries removes that entity from the visible schema.

For example:
```sql
revoke all privileges on public."Account" from api_user;
```

removes the `Account` GraphQL type.

Similarly, revoking `SELECT` access on a table's column will remove that field from the associated GraphQL type/s.

The permissions `SELECT`, `INSERT`, `UPDATE`, and `DELETE` all impact the relevant sections of the GraphQL schema.


## Row Visibilty

Visibility of rows in a given table can be configured using PostgreSQL's built-in [row level security](https://www.postgresql.org/docs/current/ddl-rowsecurity.html) policies.

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 if/how those entities are reflected into the GraphQL schema.
Comment directives are snippets of configuration associated with SQL entities that alter how those entities behave.

The format of a comment directive is

Expand Down Expand Up @@ -49,7 +31,7 @@ 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 is applied at the schema level and can be enable with:
The inflection directive can be applied at the schema level with:


```sql
Expand Down Expand Up @@ -79,7 +61,7 @@ For more fine grained adjustments to reflected names, see [renaming](#renaming).

### totalCount

`totalCount` is an opt-in field that is applied to each query type. It provides a count of the rows that match the query's filters, and ignores pagination arguments.
`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.

```graphql
type BlogPostConnection {
Expand All @@ -94,7 +76,7 @@ type BlogPostConnection {
to enable `totalCount` for a table, use the directive

```sql
comment on table blog_post is e'@graphql({"totalCount": {"enabled": true}})';
comment on table "BlogPost" is e'@graphql({"totalCount": {"enabled": true}})';
```
for example
```sql
Expand Down
56 changes: 39 additions & 17 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,54 @@

---

Query your existing PostgreSQL database with GraphQL
`pg_graphql` adds GraphQL support to your PostgreSQL database.

`pg_graphql` inspects your PostgreSQL schema and reflects a GraphQL schema with resolvers.
- [x] __Performant__
- [x] __Consistent__
- [x] __Serverless__
- [x] __Open Source__

- [x] __Performant__: [+2k requests/second](performance.md)
- [x] __Always up-to-date__: Reflected from the SQL schema
- [x] __Pagination__: Relay compliant
- [x] __Serverless__: Runs in your database with no *additional* server required
- [x] __Open Source__: Apache License 2.0
### Overview
`pg_graphql` reflects a GraphQL schema from the existing SQL schema.

!!! warning
pg_graphql is pre-alpha software under active development


### Motivation
`pg_graphql` provides an SQL schema -> GraphQL schema reflection engine and an associated GraphQL query -> SQL query transpiler.

The extension keeps schema generation, query parsing, and resolvers all neatly contained on your database. This enables any programming language that can connect to PostgreSQL to query the database via GraphQL with no additional servers, processes, or libraries.
The extension keeps schema translation and query resolution neatly contained on your database server. This enables any programming language that can connect to PostgreSQL to query the database via GraphQL with no additional servers, processes, or libraries.


### TL;DR

The SQL schema

```sql
--8<-- "docs/assets/demo_schema.sql"
create table account(
id serial primary key,
email varchar(255) not null,
created_at timestamp not null,
updated_at timestamp not null
);

create table blog(
id serial primary key,
owner_id integer not null references account(id),
name varchar(255) not null,
description varchar(255),
created_at timestamp not null,
updated_at timestamp not null
);

create type blog_post_status as enum ('PENDING', 'RELEASED');

create table blog_post(
id uuid not null default uuid_generate_v4() primary key,
blog_id integer not null references blog(id),
title varchar(255) not null,
body varchar(10000),
status blog_post_status not null,
created_at timestamp not null,
updated_at timestamp not null
);
```
Translates into a GraphQL schema exposing each table as a pageable collection with relationships defined by the foreign keys.
Translates into a GraphQL schema displayed below.

Each table receives an entrypoint in the top level `Query` type that is a pageable collection with relationships defined by its foreign keys. Tables similarly recieve entrypoints in the `Mutation` schema that enable bulk operations for insert, update, and delete.

![GraphiQL](./assets/quickstart_graphiql.png)
12 changes: 0 additions & 12 deletions docs/installation.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
Tested with PostgreSQL 14.

## Direct Server Access

First, install [libgraphqlparser](https://github.com/graphql/libgraphqlparser)

Then clone the repo and install using
Expand All @@ -17,11 +13,3 @@ To enable the extension in PostgreSQL we must execute a `create extension` state
```psql
create extension pg_graphql cascade;
```

## Hosted Databases e.g. RDS, Cloud SQL

Hosted database vendors do not provide the level of server access required to install `pg_graphql` at this time.

Given that third-party hosted databases are increasingly common, we are exploring including SQL implementations of `pg_graphql`'s C components so it can be installed as a single-file SQL script.

Stay tuned
7 changes: 4 additions & 3 deletions docs/reflection.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ SQL tables are reflected into GraphQL types with columns and foreign keys repres

By default, PostgreSQL table and column names are not adjusted when reflecting GraphQL type and field names. For example, an `account_holder` table has GraphQL type name `account_holder` and can be queried via the `account_holderCollection` field of the `Query` type.

In cases, like the previous example, where the SQL name is `snake_case`, you may want to [enable inflection](/pg_graphql/configuration/#inflection) so types are reflected as `AccountHolder` and `accountHolderCollection`.

In cases, like the previous example, where the SQL name is `snake_case`, you'll likely want to [enable inflection](/pg_graphql/configuration/#inflection) to re-case names to match GraphQL/Javascript conventions e.g. `AccountHolder` and `accountHolderCollection`.

Table, column, and relationship type and field names may also be [manually overridden](/pg_graphql/configuration/#tables-type) as needed.

## Type Conversion

### Connection Types

Connection types hande pagination best practices according to the [relay spec](https://relay.dev/graphql/connections.htm#). `pg_graphql` paginates via keyset pagination to enable consistent retrival times on every page.
Connection types hande pagination best practices according to the [relay spec](https://relay.dev/graphql/connections.htm#). `pg_graphql` uses keyset pagination to enable consistent retrival times on every page.

## Example

The following is a complete example showing how a sample SQL schema translates into a GraphQL schema.

```sql
--8<-- "docs/assets/demo_schema.sql"
```
Expand Down
20 changes: 20 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
`pg_graphql` fully respects builtin PostgreSQL role and row security.

## Table/Column Visbility

Table and column visibility in the GraphQL schema are controlled by standard PostgreSQL role permissions. Revoking `SELECT` access from the user/role executing queries removes that entity from the visible schema.

For example:
```sql
revoke all privileges on public."Account" from api_user;
```

removes the `Account` GraphQL type.

Similarly, revoking `SELECT` access on a table's column will remove that field from the associated GraphQL type/s.

The permissions `SELECT`, `INSERT`, `UPDATE`, and `DELETE` all impact the relevant sections of the GraphQL schema.

## Row Visibilty

Visibility of rows in a given table can be configured using PostgreSQL's built-in [row level security](https://www.postgresql.org/docs/current/ddl-rowsecurity.html) policies.
1 change: 1 addition & 0 deletions mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ nav:
- API: 'api.md'
- Reflection: 'reflection.md'
- Computed Fields: 'computed_fields.md'
- Security: 'security.md'
- Configuration: 'configuration.md'
- Performance: 'performance.md'
- Installation: 'installation.md'
Expand Down
1 change: 1 addition & 0 deletions test/expected/extend_type_with_generated_column.out
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ begin;
id serial primary key,
first_name varchar(255) not null,
last_name varchar(255) not null,
-- Computed Column
full_name text generated always as (first_name || ' ' || last_name) stored
);
insert into public.account(first_name, last_name)
Expand Down
1 change: 1 addition & 0 deletions test/sql/extend_type_with_generated_column.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ begin;
id serial primary key,
first_name varchar(255) not null,
last_name varchar(255) not null,
-- Computed Column
full_name text generated always as (first_name || ' ' || last_name) stored
);

Expand Down

0 comments on commit 79e0a60

Please sign in to comment.