docs: logical model references, native query relationships

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9462
Co-authored-by: Rob Dominguez <24390149+robertjdominguez@users.noreply.github.com>
GitOrigin-RevId: 29a40ebf19c60fa182449c3721bf1d8d9f2d999f
This commit is contained in:
Philip Lykke Carlsen 2023-06-08 16:01:42 +02:00 committed by hasura-bot
parent 5601e1bd1f
commit e3ba41324b
6 changed files with 466 additions and 172 deletions

View File

@ -66,8 +66,9 @@ The structure of args depends on the type and version.
The various types of queries are listed in the following table:
| `type` | `args` | `version` | Synopsis |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------ |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------- |
| **bulk** | [Query](#metadata-query) array | 1 | Execute multiple operations in a single query |
| **bulk_atomic** | [Query](#metadata-query) array | 2 | Execute multiple operations in a single **transaction**. Limited operation support. |
| **concurrent_bulk** | [Query](#metadata-query) array | 2 | Execute multiple **read only** operations in a single **transaction** |
| **bulk_keep_going** | [Query](#metadata-query) array | 1 | Like `bulk`, but subcommands can fail without the whole batch failing |
| [pg_add_source](/api-reference/metadata-api/source.mdx#metadata-pg-add-source) | [pg_add_source_args](/api-reference/metadata-api/source.mdx#metadata-pg-add-source-syntax) | 1 | Add a Postgres database |

View File

@ -52,8 +52,9 @@ X-Hasura-Role: admin
}
```
The type of each field can be any valid [PostgreSQL data type](/schema/postgres/postgresql-types.mdx), and each field
can be marked as nullable or not.
The type of each field can be either a [PostgreSQL data type](/schema/postgres/postgresql-types.mdx)
or references to other Logical Models, and each field can be marked as nullable or not, see
[LogicalModelType](/api-reference/syntax-defs.mdx#logicalmodeltype).
### Args syntax {#metadata-pg-track-logical-model-syntax}

View File

@ -47,6 +47,8 @@ X-Hasura-Role: admin
"description": "<optional field description>"
}
},
"array_relationships": <Native Query relationship>,
"object_relationshps": <Native Query relationship>,
"code": "<SQL query>",
"returns": "<logical model name>"
}
@ -64,6 +66,10 @@ X-Hasura-Role: admin
| code | true | String | The SQL to run on request |
| returns | true | [LogicalModelName](/api-reference/syntax-defs.mdx#logicalmodelname) | Name of the logical model representing the resulting schema |
### Native Query relationships
See [Native Query relationship](/api-reference/syntax-defs.mdx#nativequeryrelationship).
## pg_untrack_native_query {#metadata-pg-untrack-native-query}
`pg_untrack_native_query` is used to remove a Native Query from the GraphQL schema.
@ -108,7 +114,7 @@ X-Hasura-Role: admin
"type": "query",
"arguments": {
"<name>": {
"type": "<postgres field type>",
"type": "<mssql field type>",
"nullable": false | true,
"description": "<optional field description>"
}
@ -174,7 +180,7 @@ X-Hasura-Role: admin
"type": "query",
"arguments": {
"<name>": {
"type": "<postgres field type>",
"type": "<bigquery field type>",
"nullable": false | true,
"description": "<optional field description>"
}

View File

@ -1252,12 +1252,36 @@ via [Custom Types](/api-reference/metadata-api/custom-types.mdx)
## LogicalModelField {#logicalmodelfield}
| Key | Required | Schema | Description |
| ----------- | -------- | --------- | ------------------------------------------------------------------------------------------------|
| name | true | `String` | The name of the logical model field |
| type | true | `String` | The type of the exposed column, according to the underlying data source |
| nullable | false | `Boolean` | True if the field should be exposed over the GraphQL API as a nullable field (default: `false`) |
| ----------- | -------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------|
| name | true | `String` | The name of the Logical Model field |
| type | true | [Logical Model Type](#logicalmodeltype) | A Logical Model field type |
| description | false | `String` | An extended description of the field |
## LogicalModelType {#logicalmodeltype}
A Logical Model type is one of either:
A scalar:
| Key | Required | Schema | Description |
| ----------- | -------- | --------- | ------------------------------------------------------------------------------------------------|
| scalar | true | `String` | The type of the exposed column, according to the underlying data source |
| nullable | false | `Boolean` | True if the field should be exposed over the GraphQL API as a nullable field (default: `false`) |
An array:
| Key | Required | Schema | Description |
| ----------- | -------- | --------- | ------------------------------------------------------------------------------------------------|
| array | true | [Logical Model Type](#logicalmodeltype) | A Logical Model type, which this denotes an array of |
| nullable | false | `Boolean` | True if the field should be exposed over the GraphQL API as a nullable field (default: `false`) |
A reference to another logical model:
| Key | Required | Schema | Description |
| ----------- | -------- | --------- | -------------------------------------------------------------------------------------------------------|
| logical_model | true | [Logical Model Type](#logicalmodeltype) | A Logical Model type, which this refers to. Recursive and mutually recursive references are permitted. |
| nullable | false | `Boolean` | True if the field should be exposed over the GraphQL API as a nullable field (default: `false`) |
## NativeQueryArgument {#nativequeryargument}
| Key | Required | Schema | Description |
@ -1266,6 +1290,13 @@ via [Custom Types](/api-reference/metadata-api/custom-types.mdx)
| nullable | false | `Boolean` | True if the underlying column is nullable (default: `false`) |
| description | false | `String` | An extended description of the argument |
## NativeQueryRelationship {#nativequeryrelationship}
| Key | Required | Schema | Description |
| --------------- | -------- | ------------------------------------- | ---------------------------------------------------------------- |
| remote_native_query | true | `String` | The Native Query to which the relationship has to be established |
| column_mapping | true | Object (local-column : remote-column) | Mapping of columns from current table to remote table |
## Stored Procedure Argument {#stored-procedure-argument}
| Key | Required | Schema | Description |

View File

@ -22,7 +22,7 @@ import ProductBadge from '@site/src/components/ProductBadge';
:::tip Supported from
Native queries are supported from `v2.26.0`.
Logical Models are supported from `v2.26.0`.
:::
@ -62,7 +62,7 @@ X-Hasura-Role: admin
"fields": [
{
"name": "<field name>",
"type": "<PostgreSQL field type>",
"type": "<PostgreSQL Logical Model type>",
"nullable": false | true,
"description": "<optional field description>"
},
@ -75,8 +75,9 @@ X-Hasura-Role: admin
</TabItem>
</Tabs>
The type of each field can be any valid [PostgreSQL data type](/schema/postgres/postgresql-types.mdx), and each field
can be marked as nullable or not.
The type of each field can be either a [PostgreSQL data type](/schema/postgres/postgresql-types.mdx)
or references to other Logical Models, and each field can be marked as nullable or not, see
[LogicalModelType](/api-reference/syntax-defs.mdx#logicalmodeltype).
For example, we could track a representation of an article as follows:
@ -96,24 +97,39 @@ X-Hasura-Role: admin
"fields": [
{
"name": "id",
"type": "integer"
"type":
{
"scalar": "integer"
}
},
{
"name": "title",
"type": "text"
"type":
{
"scalar": "text"
}
},
{
"name": "contents",
"type": "text"
"type":
{
"scalar": "text"
}
},
{
"name": "published_date",
"type": "published_date",
"type":
{
"scalar": "date",
"nullable": true
},
},
{
"name": "is_published",
"type": "boolean"
"type":
{
"scalar": "boolean"
}
}
]
}
@ -176,6 +192,110 @@ X-Hasura-Role: admin
</TabItem>
</Tabs>
## Referencing other logical models {#referencing-other-logical-models}
Logical Model fields are allowed to refer to other Logical Models, even recursively, allowing nested data types.
Object or array relationships between Native Queries are an example use of this.
To elaborate on the "article" example above, we can include authors in the data model:
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "bulk",
"args":
[
{
"type": "pg_track_logical_model",
"args": {
"source": "default",
"name": "article",
"fields": [
{
"name": "id",
"type":
{
"scalar": "integer"
}
},
{
"name": "title",
"type":
{
"scalar": "text"
}
},
{
"name": "contents",
"type":
{
"scalar": "text"
}
},
{
"name": "author_id",
"type":
{
"scalar": "integer"
}
},
{
"name": "author",
"type":
{
"logical_model": "author",
},
}
]
}
},
{
"type": "pg_track_logical_model",
"args": {
"source": "default",
"name": "author",
"fields": [
{
"name": "id",
"type":
{
"scalar": "integer"
}
},
{
"name": "name",
"type":
{
"scalar": "text"
}
},
{
"name": "articles",
"type":
{
"array":
{
"logical_model": "article"
}
}
}
]
}
}
]
}
```
</TabItem>
</Tabs>
## Permissions
By default, a model has no permissions, and only the admin account will be able to use it. You can enable the model by
@ -278,7 +398,3 @@ X-Hasura-Role: admin
</TabItem>
</Tabs>
## Relationships
Currently, Logical Models do not support relationships. They will be supported in a future release.

View File

@ -276,6 +276,19 @@ X-Hasura-Role: admin
"description": "<optional field description>"
}
},
"array_relationships": [
{
"name": "<relationship name>",
"using": {
"column_mapping": {
"<local column>": "<remote column>"
},
"remote_native_query: "<remote native query name>"
}
}
],
"object_relationships": <same as array_relationships>,
"description": "<text>",
"code": "<SQL query>",
"returns": "<logical model name>"
}
@ -345,3 +358,129 @@ A future release will allow mutations to be specified using native queries.
Native queries will inherit the permissions of the Logical Model that they return. See the
[documentation on Logical Models](/schema/postgres/logical-models/index.mdx) for an explanation of how to add
permissions.
## Relationships
Relationships are supported between Native Queries.
This is how Native Queries may implement object and array fields of their referenced Logical Model.
Unlike tables, relationships for a Native Query have to be given as part of
tracking the Native Query: The schema of a Native Query is defined by its
Logical Model, and the Native Query needs to implement all the fields of the
Logical Model in order to be tracked successfully.
Currently relationships are only supported between Native Queries residing in the same source.
As an example, consider the following Native Queries which implement the data
model of articles and authors given in the section on [Logical Model references](/schema/postgres/logical-models/index.mdx#referencing-other-logical-models):
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "bulk_atomic",
"args":
[
{ "args": {
"arguments": {
"length": {
"nullable": false,
"type": "integer"
}
},
"array_relationships": [],
"code": "
SELECT
id,
title,
(substring(content, 1, {{length}}) ||
(CASE WHEN length(content) < {{length}}
THEN '' ELSE '...' END))
AS contents,
date
FROM article",
"object_relationships": [
{
"name": "author",
"using": {
"column_mapping": {
"author_id": "id"
},
"remote_native_query": "get_authors"
}
}
],
"returns": "article",
"root_field_name": "get_articles",
"source": "postgres",
"type": "query"
},
"type": "pg_track_native_query"
},
,{ "args": {
"arguments": {},
"array_relationships": [
{
"name": "articles",
"using": {
"column_mapping": {
"id": "author_id"
},
"remote_native_query": "get_articles"
}
}
],
"code": "SELECT * FROM authors",
"object_relationships": [],
"returns": "author",
"root_field_name": "get_authors",
"source": "postgres",
"type": "query"
},
"type": "pg_track_native_query"
}
]
}
```
:::info Wrap calls in `bulk_atomic`
Similar to Logical Models, tracking the Native Queries one-by-one would fail,
since `get_articles` refers to `get_authors`, which is not yet defined.
Tracking the Native Queries in one atomic operation postpones coherency checks
until all models are tracked, which allows for mutual references.
:::
</TabItem>
<TabItem value="query" label="Query">
The Native Queries in this example enable queries like:
```graphql
query {
get_authors
{
name
short_excerpt: articles(args: {length: 10})
{
title
contents
}
long_excerpt: articles(args: {length: 100})
{
title
contents
}
}
}
```
</TabItem>
</Tabs>