Initial docs for Snowflake native queries

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10225
Co-authored-by: Rob Dominguez <24390149+robertjdominguez@users.noreply.github.com>
GitOrigin-RevId: e72daa4a5f3d53c76ca9ccb22db693120f36d743
This commit is contained in:
Brandon Martin 2023-08-29 08:21:44 -06:00 committed by hasura-bot
parent 114261533b
commit 0b05c6490d
2 changed files with 1286 additions and 0 deletions

View File

@ -0,0 +1,569 @@
---
sidebar_label: Logical Models
sidebar_position: 4
description: Customize the Hasura GraphQL schema with Logical Models
keywords:
- hasura
- docs
- snowflake
- schema
- Logical Models
- Native Queries
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Thumbnail from '@site/src/components/Thumbnail';
# Snowflake: Logical Models
## Introduction
:::tip Supported from
Logical Models are supported from `v2.33.0`.
:::
Logical Models are a GraphQL representation of database data. They provide an abstraction over the underlying database.
Logical Models are a new approach from Hasura and are currently used by the
[Native Queries](/schema/snowflake/native-queries.mdx) and the
GraphQL API for a native database query.
You can find examples of how to use Logical Models in the
[Native Queries](/schema/snowflake/native-queries.mdx) documentation. For a more detailed explanation
of Logical Models themselves, read on.
## Tracking a Logical Model
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
You can create a Logical Model from the "Data" tab of the Console, by clicking on `Native Queries` in the sidebar, then
`Add Logical Model`:
<Thumbnail src="/img/native-queries/logical-model-add.png" alt="Create Logical Model" width="800px" />
</TabItem>
<TabItem value="cli" label="CLI">
You can create a logical model by adding it to the appropriate database definition in the `metadata > databases > databases.yaml`
file:
```yaml
logical_models:
- name: "<name>"
fields:
"<field name>":
type: "<Snowflake field type>"
nullable: false | true
description: "<optional field description>"
...
```
</TabItem>
<TabItem value="api" label="API">
You create a logical model through the metadata API:
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_track_logical_model",
"args": {
"source": "default",
"name": "<name>",
"fields": [
{
"name": "<field name>",
"type": "<Snowflake field type>",
"nullable": false | true,
"description": "<optional field description>"
},
...
]
}
}
```
</TabItem>
</Tabs>
The type of each field can be either a [Snowflake data type](https://docs.snowflake.com/en/sql-reference/intro-summary-data-types)
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:
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
<Thumbnail
src="/img/native-queries/create-logical-model-excerpt-example.png"
alt="Create Logical Model"
width="800px"
/>
</TabItem>
<TabItem value="cli" label="CLI">
Add the following to the `default` database definition in the `metadata > databases > databases.yaml` file:
```yaml
logical_models:
- name: article
fields:
id:
type: integer
nullable: false
title:
type: text
nullable: false
contents:
type: text
nullable: false
published_date:
type: date
nullable: true
is_published:
type: bit
nullable: false
```
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_track_logical_model",
"args": {
"source": "default",
"name": "article",
"fields": [
{
"name": "id",
"type":
{
"scalar": "int"
}
},
{
"name": "title",
"type":
{
"scalar": "text"
}
},
{
"name": "contents",
"type":
{
"scalar": "text"
}
},
{
"name": "published_date",
"type":
{
"scalar": "date",
"nullable": true
},
},
{
"name": "is_published",
"type":
{
"scalar": "bit"
}
}
]
}
}
```
</TabItem>
</Tabs>
## Untracking a Logical Model
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
To untrack a Logical Model, click `Remove` next to the Logical Model:
<Thumbnail src="/img/native-queries/delete-logical-model.png" alt="Delete Logical Model" width="800px" />
</TabItem>
<TabItem value="cli" label="CLI">
You can remove a Logical Model by removing it from the `metadata > databases > databases.yaml` file.
</TabItem>
<TabItem value="api" label="API">
You can remove a Logical Model the same way:
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_untrack_logical_model",
"args": {
"source": "default",
"name": "<name>"
}
}
```
</TabItem>
</Tabs>
:::info Removing a Logical Model
Note that you can only remove an **unused** Logical Model; if the model is attached to a Native Query, this operation
will fail. You must remove the Native Query first.
:::
To untrack the above `article` Logical Model, we would run the following:
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
<Thumbnail src="/img/native-queries/delete-logical-model.png" alt="Delete Logical Model" width="800px" />
</TabItem>
<TabItem value="cli" label="CLI">
Remove the above metadata from the `metadata > databases > databases.yaml` file.
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_untrack_logical_model",
"args": {
"source": "default",
"name": "article"
}
}
```
</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_atomic",
"args":
[
{
"type": "snowflake_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": "snowflake_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"
}
}
}
]
}
}
]
}
```
:::info Wrap calls in `bulk_atomic`
Tracking the Logical Models one-by-one would fail, since `article` refers to `author`, which is not yet defined.
Tracking the Logical Models in one atomic operation postpones coherency checks until all models are tracked, which
allows for mutual references.
:::
</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
adding permissions for a given role.
As Logical Models are currently only used for read-only purposes, you can only add select permissions.
The permissions consist of a list of columns that the role can access, and a filter that specifies which rows the role
can receive.
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
<Thumbnail src="/img/native-queries/create-permissions.png" alt="Create Logical Model Permissions" width="800px" />
</TabItem>
<TabItem value="cli" label="CLI">
Columns must be specified, though you can use `"*"` to specify that you want to allow all columns.
The filter is the same boolean expression syntax as [query filters](/queries/ms-sql-server/query-filters.mdx). To allow
all rows to be passed through to the response, you can specify an empty filter, `{}`.
Add the required permissions to the relevant logical model in `metadata > databases > databases.yaml`:
```yaml
logical_models:
- name: "<name>"
fields:
...
select_permissions:
- role: "<role name>"
permission:
columns: "*" | [
"column 1",
"column 2",
...
]
filter: "<boolean expression>"
- ...
```
</TabItem>
<TabItem value="api" label="API">
Columns must be specified, though you can use `"*"` to specify that you want to allow all columns.
The filter is the same boolean expression syntax as [query filters](/queries/ms-sql-server/query-filters.mdx). To allow
all rows to be passed through to the response, you can specify an empty filter, `{}`.
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_create_logical_model_select_permission",
"args": {
"source": "default",
"name": "<logical model name>",
"role": "<role name>",
"permission": {
"columns": "*" | [
"column 1",
"column 2",
...
],
"filter": <boolean expression>
}
}
}
```
</TabItem>
</Tabs>
For example, to allow access to the `article` Logical Model for the `reader` role, but only for published articles, we
could use the following permission to limit the accessible rows to those where `is_published` is `true`, and then hide
that column from the list (by specifying all other columns).
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
<Thumbnail src="/img/native-queries/permissions-with-check.png" alt="Permissions with check" width="800px" />
</TabItem>
<TabItem value="cli" label="CLI">
Add the required permissions to the relevant logical model in `metadata > databases > databases.yaml`:
```yaml
logical_models:
- name: '<name>'
fields: ...
select_permissions:
- role: reader
permission:
columns:
- id
- title
- contents
- date
filter:
is_published:
_eq: true
- ...
```
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_create_logical_model_select_permission",
"args": {
"source": "default",
"name": "article",
"role": "reader",
"permission": {
"columns": [
"id",
"title",
"contents",
"date"
],
"filter": {
"is_published": {"_eq": true}
}
}
}
}
```
</TabItem>
</Tabs>
You can also drop permissions:
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
<Thumbnail src="/img/native-queries/delete-permissions.png" alt="Delete Permissions" width="800px" />
</TabItem>
<TabItem value="cli" label="CLI">
Remove the relevant permission from `metadata > databases > databases.yaml`.
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_drop_logical_model_select_permission",
"args": {
"source": "default",
"name": "<logical model name>",
"role": "<role name>"
}
}
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,717 @@
---
sidebar_label: Native Queries
sidebar_position: 4.1
description: Customize the Hasura GraphQL schema with Native Queries
keywords:
- hasura
- docs
- snowflake
- schema
- Logical Models
- Native Queries
---
import ProductBadge from '@site/src/components/ProductBadge';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Thumbnail from '@site/src/components/Thumbnail';
# Snowflake: Native Queries
<div className="badge-container">
<ProductBadge standard pro ee self />
</div>
## What are Native Queries?
:::tip Supported from
Native queries are supported from `v2.33.0`.
:::
The Hasura GraphQL Engine automatically generates a GraphQL API around database objects. That includes querying,
mutating, and subscribing to data changes and events. However, sometimes we need more custom or advanced behavior that
doesnt come out of the box.
Native Queries allows you to automatically generate a GraphQL API around raw SQL queries, giving you more flexibility
and control over your Hasura-generated GraphQL schema. They allow you to harness the full power of SQL within Hasura
without the need to create database objects that require DDL privileges.
You might find Native Queries useful for many reasons:
- Use the full power of SQL that Hasura might not provide access to through the typical table API, such as `GROUP BY`,
window functions, or scalar functions.
- Provide custom arguments to the users of your API to greatly expand its flexibility.
- Encapsulate sophisticated filtering with a query, allowing your users to provide a single argument rather than having
to understand how to manipulate the data.
- Work with the advanced features of your database to improve performance.
- Write a compatibility layer around tables, making it easier to change your API without breaking existing clients.
- Reduce duplication by moving common data manipulation into one place.
Native Queries are a Cloud and Enterprise feature of Hasura.
:::info Supported features
Currently, Hasura aggregations are not supported, but you can write the aggregation yourself as part of the query.
Relationships will be supported in a future release.
:::
## Example: excerpts of articles
Well start with an example. Lets use this new feature to add some custom functionality to our Hasura API, without
needing to define a custom SQL function on the database. If youd like some reference documentation, scroll down, and
also take a look at the [Logical Models documentation](/schema/snowflake/logical-models.mdx).
Imagine we have some articles in a table, with content kindly donated by [Loripsum.net](https://loripsum.net/):
```sql
CREATE TABLE article(
id INTEGER NOT NULL AUTOINCREMENT PRIMARY KEY,
title TEXT NOT NULL,
date DATE NOT NULL,
content TEXT NOT NULL
);
INSERT INTO article(title, date, content) VALUES
('You will not believe', '2023-01-01', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Facillimum id quidem est, inquam. Esse enim, nisi eris, non potes. Oratio me istius philosophi non offendit; Idemne, quod iucunde? Quid est enim aliud esse versutum? Non autem hoc: igitur ne illud quidem.'),
('Ten things that', '2023-02-02', 'Illi enim inter se dissentiunt. Sedulo, inquam, faciam. Simus igitur contenti his.'),
('Did you know', '2023-03-03', 'Ratio quidem vestra sic cogit. Duo Reges: constructio interrete. An nisi populari fama? Erat enim res aperta. Apparet statim, quae sint officia, quae actiones. Tum mihi Piso: Quid ergo?'),
('They just cannot', '2023-04-04', 'Itaque hic ipse iam pridem est reiectus; Quod quidem iam fit etiam in Academia. Negare non possum. Quis non odit sordidos, vanos, leves, futtiles?'),
('What on earth', '2023-05-05', 'Venit ad extremum; At certe gravius. Efficiens dici potest. Rhetorice igitur, inquam, nos mavis quam dialectice disputare? Nunc de hominis summo bono quaeritur; Rationis enim perfectio est virtus;');
```
When listing these articles in an index, we probably want to truncate the text to, lets say, 20 characters. So lets
create a Logical Model representing the excerpted article:
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
Click on the `Logical Models` tab, and on the `Add Logical Model` button.
<Thumbnail src="/img/native-queries/logical-model-add.png" alt="Create Logical Model" width="800px" />
Once the modal is open, fill in the form. Each added field will be returned as a field in the GraphQL schema.
<Thumbnail
src="/img/native-queries/create-logical-model-excerpt-example.png"
alt="Create Logical Model"
width="800px"
/>
</TabItem>
<TabItem value="cli" label="CLI">
Add the following to the `default` database definition in the `metadata > databases > databases.yaml` file:
```yaml
logical_models:
- name: article_excerpt
fields:
id:
type: integer
title:
type: text
date:
type: date
excerpt:
type: text
```
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_track_logical_model",
"args": {
"source": "default",
"name": "article_excerpt",
"fields": [
{
"name": "id",
"type": "integer"
},
{
"name": "title",
"type": "text"
},
{
"name": "date",
"type": "date"
},
{
"name": "excerpt",
"type": "text"
}
]
}
}
```
</TabItem>
</Tabs>
We can then track a Native Query that takes a single argument, `max_length`, and uses it to truncate the article content
(more on arguments below). We use the SQL `substring` function to truncate the function, and the `length` function to
decide whether we should use an ellipsis.
We use `{{max_length}}` to refer to the argument. We need it twice, so we simply use the argument twice.
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
Click on the `Native Queries` tab and `Create Native Query` button.
<Thumbnail src="/img/native-queries/native-query-create.png" alt="Create Native Query" width="1146px" />
Then, fill in the form with the data required:
| Field | Value |
| -------------------------- | ------------------------------- |
| Native Query name | `article_with_excerpt` |
| Database | The database to be used |
| Input parameter | `max_length`, of type `integer` |
| The Native Query statement | Value below 👇 |
```sql
SELECT id, title, (substring(content, 1, {{max_length}}) || (CASE WHEN length(content) < {{max_length}} THEN '' else '...' END)) AS excerpt, date
FROM article
```
Finally, at the end, add the Query Return Type as the `article_excerpt` Logical Model we created and click `Save`:
<Thumbnail
src="/img/native-queries/create-native-query-excerpt-example.png"
alt="Create Native Query Form"
width="1146px"
/>
</TabItem>
<TabItem value="cli" label="CLI">
Add the following to the `default` database definition in the `metadata > databases > databases.yaml` file:
```yaml
native_queries:
- root_field_name: article_with_excerpt
arguments:
max_length:
type: integer
code:
SELECT id as "id", title as "title", (substring(content, 1, {{max_length}}) || (CASE WHEN length(content) < {{max_length}} THEN ''
else '...' END)) AS "excerpt", date as "date" FROM article
returns: article_excerpt
```
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_track_native_query",
"args": {
"type": "query",
"source": "default",
"root_field_name": "article_with_excerpt",
"arguments": {
"max_length": {
"type": "integer"
}
},
"returns": "article_excerpt",
"code": "SELECT id, title, (substring(content, 1, {{max_length}}) || (CASE WHEN length(content) < {{max_length}} THEN '' else '...' END)) AS excerpt, date FROM article"
}
}
```
</TabItem>
</Tabs>
All thats left is for us to make a GraphQL query to select some articles with excerpts using our new root field
generated in the previous API call. All we need to provide is the date range were interested in:
```graphql
query {
article_with_excerpt(args: { max_length: 20 }, where: { date: { _gte: "2023-03-01" } }) {
id
title
date
excerpt
}
}
```
When we run this GraphQL query, we get the following results:
```json
{
"data": {
"article_with_excerpt": [
{
"id": 3,
"title": "Did you know",
"date": "2023-03-03",
"excerpt": "Ratio quidem vestra ..."
},
{
"id": 4,
"title": "They just cannot",
"date": "2023-04-04",
"excerpt": "Itaque hic ipse iam ..."
},
{
"id": 5,
"title": "What on earth",
"date": "2023-05-05",
"excerpt": "Venit ad extremum; A..."
}
]
}
}
```
## Creating a Native Query
:::info All fields in Snowflake are required to use `as "field"` syntax in your native query SQL
When writing your queries for Snowflake you must use `as "field"` syntax for all returning fields. From the `article` example above:
```sql
SELECT id as "id", title as "title", (substring(content, 1, {{max_length}}) || (CASE WHEN length(content) < {{max_length}} THEN ''
else '...' END)) AS "excerpt", date as "date" FROM article
```
Notice that each field that we are returning we provide the `as "field"`.
:::
### 1. Create a Logical Model
In order to represent the structure of the data returned by the query, we first create a Logical Model.
:::info Permissions and Logical Models
Note that this Logical Model has no attached permissions and therefore will only be available to the admin role. See the
[Logical Model documentation](/schema/ms-sql-server/logical-models.mdx) for information on attaching permissions.
:::
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
To get started choose `Native Queries` from the sidebar in the `Data` tab:
<Thumbnail src="/img/native-queries/native-queries-menu.png" alt="Create Logical Model" width="750px" />
Click on the `Logical Models` tab, and on the `Add Logical Model` button.
<Thumbnail src="/img/native-queries/logical-model-add.png" alt="Create Logical Model" width="800px" />
Once the modal is open, fill in the forms with:
| Field | Value |
| ------------------ | ----------------------------- |
| Source | The database to be used |
| Logical Model Name | The name of the Logical Model |
Finally, add any optional fields that you would like to be included in the Logical Model and click
`Create Logical Model`.
<Thumbnail src="/img/native-queries/logical-model-modal.png" alt="Create Logical Model" width="800px" />
</TabItem>
<TabItem value="cli" label="CLI">
You can create a logical model by adding it to the appropriate database definition in the `metadata > databases > databases.yaml`
file:
```yaml
logical_models:
- name: "<name>"
fields:
"<field name>":
type: "<Snowflake field type>"
nullable: false | true
description: "<optional field description>"
...
```
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_track_logical_model",
"args": {
"source": "default",
"name": "<name>",
"fields": [
{
"name": "<field name>",
"type": "<Snowflake field type>",
"nullable": false | true,
"description": "<optional field description>"
},
...
]
}
}
```
</TabItem>
</Tabs>
### 2. Create a Native Query
Once the Logical Model is defined, we can use it to define the query:
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="console" label="Console">
Click on the `Native Queries` tab and `Create Native Query` button.
<Thumbnail src="/img/native-queries/native-query-create.png" alt="Create Native Query" width="1146px" />
Then, fill in the form with the data required:
| Field | Value |
| -------------------------- | ------------------------------- |
| Native Query name | `article_with_excerpt` |
| Database | The database to be used |
| Input parameter | `max_length`, of type `integer` |
| The Native Query statement | Your SQL statement. |
| Query Return Type | The Logical Model created above |
Finally, click `Save`.
<Thumbnail src="/img/native-queries/create-native-query.png" alt="Create Native Query Form" width="1146px" />
</TabItem>
<TabItem value="cli" label="CLI">
Add the following to the relevant database definition in the `metadata > databases > databases.yaml` file:
```yaml
native_queries:
- root_field_name: "<root field name>"
arguments:
"<argument name>":
type: "<PostgreSQL field type>"
nullable: false | true
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>"
```
</TabItem>
<TabItem value="api" label="API">
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "snowflake_track_native_query",
"args": {
"source": "default",
"root_field_name": "<name>",
"type": "query",
"arguments": {
"<name>": {
"type": "<Snowflake field type>",
"nullable": false | true,
"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>"
}
}
```
</TabItem>
</Tabs>
You can use any SQL that you could potentially use in a parameterized query, with the following caveats:
- The query must currently be a single read-only SQL query.
- The query must be a valid standalone query, and not a partial query.
- The return type of the query must match with the Logical Model.
- The SQL cannot invoke a stored procedure.
#### Arguments
The query can take arguments, which are specified in the metadata. These arguments can be used in the SQL using the
syntax `{{argument_name}}`. This syntax resembles popular string templating languages such as Mustache, but does not use
string interpolation. Instead, it works in exactly the same way as parameterized queries in the database, and so
arguments do not need escaping or quoting in the SQL itself. They will be treated as variables of the correct type.
This does mean that arguments cannot be used for elements of the SQL that deal with structure. For example, you cannot
use an argument to specify the name of the table in a `FROM` clause.
When making a query, the arguments are specified using the `args` parameter of the query root field.
##### Example: `LIKE` operator
A commonly used operator is the `LIKE`. When used in a `WHERE` condition, it's usually written with this syntax
`WHERE Title LIKE '%word%'`.
In order to use it with Native Query arguments, you need to use this syntax `LIKE ('%' || {{searchTitle}} || '%')`,
where `searchTitle` is the Native Query parameter.
## Using the Native Query
You can make a GraphQL request using the specified root field name just as you would any other GraphQL query. When
making a query, the arguments are specified using the `args` parameter of the query root field.
```graphql
query {
<root field name>(
[args: {"<argument name>": <argument value>, ...},]
[where: ...,]
[order_by: ..., distinct_on: ...,]
[limit: ..., offset: ...]
) {
<field 1>
<field 2>
...
}
}
```
## Query functionality
Just like tables, Native Queries generate GraphQL types with the ability to further break down the data. You can find
more information in the relevant documentation for [filtering](/queries/ms-sql-server/query-filters.mdx),
[sorting](/queries/ms-sql-server/sorting.mdx), and [pagination](/queries/ms-sql-server/pagination.mdx).
Subscriptions (live queries) are also supported as usual.
## Mutations
Currently, only read-only queries are supported. All queries are run in a read-only transaction where supported to
enforce this constraint.
A future release will allow mutations to be specified using Native Queries.
## Permissions
Native queries will inherit the permissions of the Logical Model that they return. See the
[documentation on Logical Models](/schema/ms-sql-server/logical-models.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/ms-sql-server/logical-models.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": [
{
"type": "snowflake_track_logical_model",
"args": {
"description": "",
"fields": [
{
"name": "id",
"nullable": false,
"type": "integer"
},
{
"name": "title",
"nullable": false,
"type": "varchar"
},
{
"name": "author_id",
"nullable": false,
"type": "integer"
},
{
"name": "author",
"type": {
"logical_model": "author",
"nullable": false
}
}
],
"name": "article",
"source": "snowflake"
}
},
{
"type": "snowflake_track_logical_model",
"args": {
"description": "",
"fields": [
{
"name": "id",
"nullable": false,
"type": "integer"
},
{
"name": "name",
"nullable": false,
"type": "varchar"
},
{
"name": "articles",
"type": {
"array": {
"logical_model": "article"
},
"nullable": false
}
}
],
"name": "author",
"source": "snowflake"
}
},
{
"type": "snowflake_track_native_query",
"args": {
"arguments": {},
"array_relationships": [],
"code": "SELECT * FROM (VALUES (1, 'Logical Models', 1), (2, 'Native Queries', 2), (3, 'Relationships', 3), (4, 'Graph Relationships', 4), (5, 'Permissions', 5)) as t(\"id\", \"title\", \"author_id\")",
"object_relationships": [
{
"name": "author",
"using": {
"column_mapping": {
"author_id": "id"
},
"insertion_order": null,
"remote_native_query": "author"
}
}
],
"returns": "article",
"root_field_name": "article",
"source": "snowflake",
"type": "query"
}
},
{
"type": "snowflake_track_native_query",
"args": {
"arguments": {},
"array_relationships": [
{
"name": "articles",
"using": {
"column_mapping": {
"id": "author_id"
},
"insertion_order": null,
"remote_native_query": "article"
}
}
],
"code": "SELECT * FROM (VALUES (1, 'Tom'), (2, 'Dan'), (3, 'Philip'), (4, 'Gil'), (5, 'Samir')) as t(\"id\", \"name\")",
"object_relationships": [],
"returns": "author",
"root_field_name": "author",
"source": "snowflake",
"type": "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>