refactor docs schema section (#3489)

This commit is contained in:
Rikin Kachhia 2019-12-26 17:35:37 +05:30 committed by GitHub
parent 445061b99f
commit 3a7a3bf6bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 294 additions and 121 deletions

View File

@ -44,4 +44,4 @@ Follow the example at :doc:`access control basics <basics>`.
roles-variables
permission-rules
common-roles-auth-examples
role-multiple-rules

View File

@ -0,0 +1,118 @@
Multiple column + row permissions for the same role
===================================================
.. contents:: Table of contents
:backlinks: none
:depth: 1
:local:
Use case
--------
In some cases we might want to allow access to certain columns for a role only if a particular condition is met
while allowing access to other columns based on a different condition
i.e. have different column permissions based on different row permissions.
Currently it is not possible to define multiple column + row permission rules for the same role.
We can work around this limitation by using :ref:`views <custom_views>`.
**Example**
Let's say we have a table called ``user_info`` with columns ``(id, name, city, email, phone, address)``.
We want the role ``user`` to be able to access:
- the ``email``, ``phone`` and ``address`` columns only if the ``id`` column is the requesting user's id i.e. the current
user is the owner of the row.
- the ``id``, ``name`` and ``city`` columns for all rows.
We can achieve this via the following steps:
Step 1: Create a view
---------------------
Create a :ref:`view <create_views>` called ``user_private`` with columns ``(user_id, email, phone, address)``:
.. code-block:: SQL
CREATE VIEW user_private AS
SELECT id AS user_id, email, phone, address
FROM user_info;
Step 2: Create a relationship
-----------------------------
For the table ``user_info``, create a :ref:`manual object relationship <create_manual_relationships>` called
``private_info`` using ``user_info : id -> user_private : user_id``:
.. thumbnail:: ../../../../img/graphql/manual/auth/multiple-rules-create-manual-relationship.png
Step 3: Define permissions
--------------------------
For the role ``user``, create the following permissions for ``select``:
- Table ``user_info``: allow access to ``id``, ``name`` and ``city`` without any row conditions.
.. thumbnail:: ../../../../img/graphql/manual/auth/multiple-rules-define-public-permissions.png
- View ``user_private``: allow access to ``id``, ``phone``, ``email`` and ``address`` if the ``user-id``
passed in the session variable is equal to the row's ``user_id``.
.. thumbnail:: ../../../../img/graphql/manual/auth/multiple-rules-define-private-permissions.png
Step 4: Query with appropriate access control
---------------------------------------------
Now we can fetch the required data with the appropriate access control by using the relationship.
If the ``X-Hasura-Role`` and the ``X-Hasura-User-Id`` session variables are set to ``user`` and ``2`` respectively, we'll get the following result:
.. graphiql::
:view_only:
:query:
query {
user_info {
id
name
city
private_info {
email
phone
address
}
}
}
:response:
{
"data": {
"user_info": [
{
"id": 1,
"name": "Julie",
"city": "Boston",
"private_info": null
},
{
"id": 2,
"name": "Josh",
"city": "Bangalore",
"private_info": {
"email": "josh@josh.com",
"phone": "+91-9787675678",
"address": "#141, 7th Main Road, Koramangala 3rd Block",
}
},
{
"id": 3,
"name": "John",
"city": "Berlin",
"private_info": null
}
]
}
}
Observe that the ``private_info`` field is returned as ``null`` for all rows without the appropriate access.

View File

@ -0,0 +1,19 @@
Guides: Data modelling
======================
.. contents:: Table of contents
:backlinks: none
:depth: 1
:local:
- :ref:`soft_deletes`
- :ref:`one_to_one_modelling`
- :ref:`one_to_many_modelling`
- :ref:`many_to_many_modelling`
.. toctree::
:maxdepth: 1
:titlesonly:
:hidden:
soft-deletes

View File

@ -1,3 +1,5 @@
.. _soft_deletes:
Setting up soft deletes for data
================================
@ -18,7 +20,7 @@ there is a timestamp value present, the record should be treated as deleted.
**For example:** Let's imagine that we have a simple Todo application, our ``todos`` table would resemble
the following:
.. thumbnail:: ../../../img/graphql/manual/schema/soft-deletes-example-data.png
.. thumbnail:: ../../../../img/graphql/manual/guides/soft-deletes-example-data.png
In this example we only have two todos, one has ``deleted_at`` with a timestamp value and the other contains a
``null`` value. The todo with the timestamp value in ``deleted_at`` represents a deleted todo and was deleted at
@ -72,15 +74,15 @@ Here are some typical rules we should set:
**Delete permissions** - remove all access
.. thumbnail:: ../../../img/graphql/manual/schema/soft-deletes-delete-perms.png
.. thumbnail:: ../../../../img/graphql/manual/guides/soft-deletes-delete-perms.png
**Insert permissions** - remove access for inserting into ``deleted_at`` column
.. thumbnail:: ../../../img/graphql/manual/schema/soft-deletes-insert-perms.png
.. thumbnail:: ../../../../img/graphql/manual/guides/soft-deletes-insert-perms.png
**Update permissions** - allow access for updating ``deleted_at`` column
.. thumbnail:: ../../../img/graphql/manual/schema/soft-deletes-update-perms.png
.. thumbnail:: ../../../../img/graphql/manual/guides/soft-deletes-update-perms.png
Step 4: Restrict access to soft-deleted records
@ -94,7 +96,7 @@ access to the ``todos`` table.
For example, let's say that a role ``user`` can only access non-deleted todos, we need to add the following
permission rule to ensure this:
.. thumbnail:: ../../../img/graphql/manual/schema/soft-deletes-select-perms.png
.. thumbnail:: ../../../../img/graphql/manual/guides/soft-deletes-select-perms.png
Now the role ``user`` can only access non-deleted ``todos``:

View File

@ -10,6 +10,7 @@ Guides / Tutorials / Resources
:maxdepth: 2
:titlesonly:
Data modelling guides <data-modelling/index>
Deployment guides <deployment/index>
Sample apps & boilerplates <sample-apps/index>
Integration/migration tutorials <integrations/index>

View File

@ -326,7 +326,7 @@ A nested insert mutation is processed as follows:
Many-to-many relationships
^^^^^^^^^^^^^^^^^^^^^^^^^^
Let's say the ``articles`` has a :ref:`many-to-many relationship <many-to-many-modelling>` with the ``tags`` table via
Let's say the ``articles`` has a :ref:`many-to-many relationship <many_to_many_modelling>` with the ``tags`` table via
a bridge table ``article_tags``.
**Example:** Insert an ``article`` along with a few ``tags``.

View File

@ -15,6 +15,11 @@ The **name of the aggregate field** is of the form ``<field-name> + _aggregate``
Common aggregation functions are ``count``, ``sum``, ``avg``, ``max``, ``min``, etc. You can see the complete
specification of the aggregate field in the :ref:`API reference <AggregateObject>`.
.. note::
For more advanced use cases, you can use :ref:`views <custom_views>` or
:ref:`custom SQL functions <custom_sql_functions>`.
Fetch aggregated data of an object
----------------------------------
@ -184,4 +189,3 @@ and articles.
]
}
}

View File

@ -1,78 +0,0 @@
Restrict access to certain fields
=================================
.. contents:: Table of contents
:backlinks: none
:depth: 2
:local:
If you want to restrict access to sensitive fields in a table, you can either use views to expose only the safe fields
or :ref:`restrict access via permissions <col-level-permissions>`.
The following section describes setting up a view for this purpose.
**For example**: Say we have a table ``user_profile (id, name, email, phone, address)``, to restrict users to
only have access to the ``id``, ``name`` & ``email`` fields of other users, we can:
Step 1: Create a view
---------------------
Open the Hasura console and head to the ``Data -> SQL`` tab.
Create a view with data from only the required (or public) columns:
.. code-block:: SQL
CREATE VIEW user_public AS
SELECT id, name, email
FROM user_profile;
Step 2: Modify permissions
--------------------------
You will need to revoke permission (if already granted) from the source table and grant access to the newly created
view. So, in our example, we do the following:
#. Remove **select** permissions from the ``user_profile`` table
#. Grant **select** permissions to the ``user_public`` view
Step 3: Query the view
----------------------
You can now query the newly created view like you would a regular table:
.. graphiql::
:view_only:
:query:
query {
user_public {
id
name
email
}
}
:response:
{
"data": {
"user_public": [
{
"id": 1,
"name": "Justin",
"email": "justin@xyz.com"
},
{
"id": 2,
"name": "Beltran",
"email": "beltran@xyz.com"
},
{
"id": 3,
"name": "Sidney",
"email": "sidney@xyz.com"
},
{
"id": 4,
"name": "Angela",
"email": "angela@xyz.com"
}
]
}
}

View File

@ -61,7 +61,4 @@ based on a typical author/article schema for reference.
pagination
Using multiple arguments <multiple-arguments>
multiple-queries
custom-functions
derived-data
control-access
variables-aliases-fragments-directives

View File

@ -9,15 +9,17 @@ Computed fields
What are computed fields?
-------------------------
Computed fields are virtual values or objects that are dynamically computed and can be queried along with a table's columns.
Computed fields are computed when requested for via SQL functions using other columns of the table and other custom inputs if needed.
Computed fields are virtual values or objects that are dynamically computed and can be queried along with a table's
columns. When requested for, computed fields are computed via SQL functions using the other columns of the table and
any user inputs if needed.
.. note::
Computed fields are only exposed over the GraphQL API and the database schema is not modified on addition of a computed field.
Computed fields are only exposed over the GraphQL API and the database schema is not modified on addition of a
computed field.
Supported SQL functions
***********************
-----------------------
Only functions which satisfy the following constraints can be added as a computed field to a table.
(*terminology from* `Postgres docs <https://www.postgresql.org/docs/current/sql-createfunction.html>`__):

View File

@ -0,0 +1,59 @@
.. _custom_field_names:
Customise auto-generated field names
====================================
.. contents:: Table of contents
:backlinks: none
:depth: 2
:local:
It is possible to override the auto-generated table and column field names exposed over the GraphQL API.
.. note::
This feature is supported in versions ``v1.0.0-beta.8`` and later.
Expose columns with a different name in the GraphQL API
-------------------------------------------------------
.. rst-class:: api_tabs
.. tabs::
.. tab:: Console
Head to the ``Data -> [table-name] -> Modify``
.. thumbnail:: ../../../img/graphql/manual/schema/custom-field-name-column.png
.. tab:: Metadata API
A custom field name can be set for a column via the following 2 methods:
- passing a :ref:`table_config` with the :ref:`CustomColumnNames` to the :ref:`track_table_v2` API while
tracking a table
- using the :ref:`set_table_custom_fields` API to set the :ref:`CustomColumnNames`
Expose table root fields with a different name in the GraphQL API
-----------------------------------------------------------------
.. rst-class:: api_tabs
.. tabs::
.. tab:: Console
Head to the ``Data -> [table-name] -> Modify``
.. thumbnail:: ../../../img/graphql/manual/schema/custom-field-name-root-fields.png
.. tab:: Metadata API
A custom field name can be set for a table root field via the following 2 methods:
- passing a :ref:`table_config` with the :ref:`custom_root_fields` names to the :ref:`track_table_v2` API while
tracking a table
- using the :ref:`set_table_custom_fields` API to set the :ref:`custom_root_fields` names

View File

@ -1,5 +1,7 @@
Query custom SQL Functions
==========================
.. _custom_sql_functions:
Customise schema with SQL functions
===================================
.. contents:: Table of contents
:backlinks: none
@ -9,8 +11,8 @@ Query custom SQL Functions
What are custom SQL functions?
------------------------------
Custom SQL functions are user-defined SQL functions that can be used to either encapsulate some custom business
logic or extend the built-in SQL functions and operators.
Custom SQL functions are `user-defined SQL functions <https://www.postgresql.org/docs/current/sql-createfunction.html>`_
that can be used to either encapsulate some custom business logic or extend the built-in SQL functions and operators.
Hasura GraphQL engine lets you expose certain types of custom functions over the GraphQL API to allow querying them
using both ``queries`` and ``subscriptions``.
@ -43,10 +45,14 @@ Custom SQL functions can be created using SQL which can be run in the Hasura con
create and track an empty table with the required schema to support the function before executing the above
steps.
Querying custom functions using GraphQL queries
-----------------------------------------------
Use cases
---------
Let's see how we can query custom functions using a GraphQL query as via the below examples:
Custom functions are ideal solutions for retrieving some derived data based on some custom business logic that
requires user input to be calculated. If your custom logic does not require any user input, you can use
:ref:`views <custom_views>` instead.
Let's see a few example use cases for custom functions:
Example: Text-search functions
******************************
@ -294,6 +300,9 @@ function in our GraphQL API as follows:
}
}
Querying custom functions using GraphQL queries
-----------------------------------------------
Aggregations on custom functions
********************************
@ -443,7 +452,7 @@ Use the ``->>`` JSON operator to fetch the value of a session variable as shown
Permissions for custom function queries
---------------------------------------
Access control permissions configured for the ``SETOF`` table of a function are also applicable to the function itself.
:doc:`Access control permissions <../auth/authorization/permission-rules>` configured for the ``SETOF`` table of a function are also applicable to the function itself.
**For example**, in our text-search example above, if the role ``user`` doesn't have the requisite permissions to view
the table ``article``, a validation error will be thrown if the ``search_articles`` query is run using the ``user``

View File

@ -14,7 +14,7 @@ purpose. If you can express your query in SQL, define a view with it and then us
type in the GraphQL query.
.. note::
Also see :doc:`aggregation-queries` to fetch aggregation data without creating a view.
Also see :doc:`../queries/aggregation-queries` to fetch aggregation data without creating a view.
**For example**, lets see how to fetch the average article rating for each author in our author/article schema:

View File

@ -25,9 +25,10 @@ Postgres constructs.
Basics <basics>
Relationships <relationships/index>
Customise with views <views>
Customise with SQL functions <custom-functions>
Default field values <default-values/index>
Enum type fields <enums>
computed-fields
custom-field-names
Using an existing database <using-existing-database>
Setting up soft deletes <soft-deletes>
Export GraphQL schema <export-graphql-schema>

View File

@ -174,12 +174,12 @@ Fetch a list of authors and a nested list of each author's articles:
}
}
.. _relationships-without-fkey:
.. _create_manual_relationships:
Using manual relationships
--------------------------
Let's say you have a table ``author(id, name)`` and a view ``author_avg_rating(id, avg)`` which has the
Let's say you have a table ``author (id, name)`` and a view ``author_avg_rating (id, avg)`` which has the
average rating of articles for each author.
Let us now create an ``object relationship`` called ``avg_rating`` from the ``author`` table to the

View File

@ -1,4 +1,4 @@
.. _many-to-many-modelling:
.. _many_to_many_modelling:
Modelling many-to-many table relationships
==========================================

View File

@ -1,3 +1,5 @@
.. _one_to_many_modelling:
Modelling one-to-many table relationships
=========================================

View File

@ -1,3 +1,5 @@
.. _one_to_one_modelling:
Modelling one-to-one table relationships
========================================

View File

@ -1,28 +1,28 @@
.. _custom_views:
Customise schema with views
===========================
.. contents:: Table of contents
:backlinks: none
:depth: 1
:depth: 2
:local:
Use cases
---------
You may want to customise your GraphQL schema to:
What are views?
---------------
- Limit scope (i.e. expose only a subset of the columns in a table)
- Fetch derived data (aggregations like *count, average, etc.*) in queries
`Views <https://www.postgresql.org/docs/current/sql-createview.html>`_ can be used to expose the results of a custom
query as a virtual table. Views are not persisted physically i.e. the query defining a view is executed whenever
data is requested from the view.
These kinds of use cases can be supported using database views.
Hasura GraphQL engine lets you expose views over the GraphQL API to allow querying them using both ``queries`` and
``subscriptions`` just like regular tables.
Please see the following pages for details about the above use cases:
.. _create_views:
- :doc:`../queries/control-access`
- :doc:`../queries/derived-data`
Creating views
--------------
Creating & exposing views
-------------------------
Views can be created using SQL which can be run in the Hasura console:
@ -31,5 +31,40 @@ Views can be created using SQL which can be run in the Hasura console:
- Select the ``Track this`` checkbox to expose the new view over the GraphQL API
- Hit the ``Run`` button
Use cases
---------
Views are ideal solutions for retrieving some derived data based on some custom business logic. If your custom logic
requires any user input, you should use :ref:`custom SQL functions <custom_sql_functions>` instead.
Let's see a few example use cases for views:
Example: Group by and then aggregate
************************************
Lets see how to fetch the average article rating for each author in our author/article schema.
A view that averages the rating of articles for each author can be created using the following SQL query:
.. code-block:: SQL
CREATE VIEW author_average_rating AS
SELECT author_id, avg(rating)
FROM article
GROUP BY author_id
Example: Hide certain fields of a table
***************************************
Say, we have some sensitive information in a table which we wouldn't want to expose. We can create a view that only
exposes the non-sensitive fields.
Let's say our ``author`` table has the fields ``id, name, city, email, phone, address`` and we want to hide the ``email``,
``phone`` and ``address`` fields. We can create the following view to achieve this:
.. code-block:: SQL
CREATE VIEW author_public AS
SELECT id, name, city
FROM author

View File

@ -157,8 +157,8 @@ Check this `sample app <https://realtime-chat.demo.hasura.app/>`__ for a working
Subscribe to the latest value of some derived data
--------------------------------------------------
In case you are interested in the latest value of some derived data, you can :doc:`create a view to query the derived
data <../queries/derived-data>` and then use subscriptions to fetch the derived value and get its latest value
In case you are interested in the latest value of some derived data, you can :ref:`create a view to query the derived
data <custom_views>` and then use subscriptions to fetch the derived value and get its latest value
whenever it updates.
Example: A poll dashboard

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB