mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
60183df1ea
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/3205 GitOrigin-RevId: ff889ce43ed613c283edefa68992eab7c36db18c
138 lines
5.5 KiB
Markdown
138 lines
5.5 KiB
Markdown
# RFC: Mutations for MSSQL Server
|
|
|
|
### Metadata
|
|
|
|
Authors: [Rakesh](http://github.com/rakeshkky)
|
|
|
|
State: Draft
|
|
|
|
Teams Involved: [Data Sources](https://github.com/orgs/hasura/teams/server-data-sources), [Docs](https://github.com/orgs/hasura/teams/hge-docs-owners) and [Console](https://github.com/orgs/hasura/teams/hge-console-owners)
|
|
|
|
Slack Channels: #team-data-sources, #feature-ms-sql
|
|
|
|
Other Docs:
|
|
- [Postgres Mutations](https://hasura.io/docs/latest/graphql/core/api-reference/graphql-api/mutation.html#graphql-api-mutation)
|
|
- [MSSQL Transactions](https://docs.microsoft.com/en-us/sql/t-sql/language-elements/transactions-transact-sql?view=sql-server-ver15)
|
|
- [MSSQL Insert Syntax](https://docs.microsoft.com/en-us/sql/t-sql/statements/insert-transact-sql?view=sql-server-ver15)
|
|
|
|
### Description
|
|
|
|
Generation and execution of GraphQL insert, delete and update mutations for MSSQL backend with permissions enforced.
|
|
|
|
### Success criteria
|
|
|
|
Taking reference to [Postgres mutations](https://hasura.io/docs/latest/graphql/core/api-reference/graphql-api/mutation.html#graphql-api-mutation)
|
|
we should able to generate schema and execute mutations for MSSQL backend.
|
|
|
|
For example, let's say a table with name `author` is tracked from a MSSQL server backend. Considering insert
|
|
mutations,
|
|
|
|
**Schema Generation**:
|
|
The server should able to generate following GraphQL schema
|
|
|
|
```graphql
|
|
|
|
type mutation_root {
|
|
insert_author(objects: [author_insert_input!]!): author_mutation_response
|
|
}
|
|
|
|
input author_insert_input{
|
|
id: Int!
|
|
name: String!
|
|
}
|
|
|
|
type author_mutation_response {
|
|
affected_rows: Int!
|
|
returning: [author!]
|
|
}
|
|
```
|
|
|
|
**Query Execution**:
|
|
The server should able to execute following sample GraphQL mutation
|
|
|
|
```graphql
|
|
|
|
mutation {
|
|
insert_author(objects: [{name: "Bob"}]){
|
|
affected_rows
|
|
returning{
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Permissions**:
|
|
Users should able to define row-level and column-level permissions for inserts via Metadata API
|
|
or Console UI
|
|
|
|
### How
|
|
|
|
```
|
|
+----------+ Schema Parser generation +----+ Translation +-----+ With transactions +-----------------+
|
|
| Metadata | --------------------------> | IR | -------------> | SQL | -------------------> | Execution on DB |
|
|
+----------+ with permissions enforced +----+ +-----+ +-----------------+
|
|
```
|
|
|
|
#### Schema Generation
|
|
Generate schema for MSSQL mutations with permissions enforced. Existing logic for Postgres schema generation
|
|
applies here with minimal changes applicable to IR abstraction.
|
|
|
|
#### Query Translation / Execution
|
|
```
|
|
+----+ +--------------+ +-----+
|
|
| IR | -------------> | Mutation AST | -----------> | SQL |
|
|
+----+ +--------------+ +-----+
|
|
```
|
|
|
|
Mutation AST is a data type which can be readily translated to SQL Text. We need to have data types for each mutation operation.
|
|
- `data Insert` for Insert
|
|
- `data Update` for Update
|
|
- `data Delete` for Delete
|
|
|
|
Specimen SQL for reference: Unlike Postgres, we cannot integrate DML statements in [common table expression](https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver15) of MSSQL. Only SELECTs are allowed in a common table expression.
|
|
Our proposal is to use [temporary tables](https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/) to capture mutated rows and generated appropriate response using SELECT statement.
|
|
|
|
```mssql
|
|
INSERT INTO test (name, age) OUTPUT INSERTED.<column1>, INSERTED.<column2> INTO #temp_table values ('rakesh', 25)
|
|
|
|
WITH some_alias AS (SELECT * FROM #temp_table)
|
|
SELECT (SELECT * FROM some_alias FOR JSON PATH, INCLUDE_NULL_VALUES) AS [returning], count(*) AS [affected_rows] FROM some_alias FOR JSON PATH, WITHOUT_ARRAY_WRAPPER;
|
|
```
|
|
|
|
For **tables without primary key**, we choose **not** to generate mutations schema atleast in the initial iterations.
|
|
|
|
|
|
#### Permissions
|
|
Like in Postgres, we need to generate expression to evaluate the check condition and return it as an extra field.
|
|
If check constraint is not satisfied we'll raise exception in the Haskell code.
|
|
|
|
```mssql
|
|
INSERT INTO test (name, age) OUTPUT INSERTED.<column1>, INSERTED.<column2> INTO #temp_table values ('rakesh', 25)
|
|
|
|
WITH alias AS (SELECT * FROM #temp_table)
|
|
SELECT (SELECT (SELECT * FROM alias FOR JSON PATH, INCLUDE_NULL_VALUES) AS [returning], count(*) AS [affected_rows] FROM alias FOR JSON PATH, WITHOUT_ARRAY_WRAPPER) AS [data], SUM(case when (id = 12) then 0 else 1 end) AS [check_constraint] FROM alias ;
|
|
|
|
```
|
|
|
|
#### Haskell interface to execute MSSQL transactions
|
|
Mutations are executed safely via database transactions.
|
|
We need to have a separate interface/library to implement [MSSQL Transactions](https://docs.microsoft.com/en-us/sql/t-sql/language-elements/transactions-transact-sql?view=sql-server-ver15).
|
|
Preferably, the library implementation details should be specified in a separate RFC. Our in-house
|
|
written [Postgres' transaction](https://github.com/hasura/pg-client-hs/blob/master/src/Database/PG/Query/Transaction.hs) library acts as good reference.
|
|
|
|
#### Testing
|
|
Generate pytests to test
|
|
- Simple mutations with returning affected rows and count
|
|
- Mutations involving all stock column types
|
|
- Mutations with permissions
|
|
|
|
Refer to [Postgres mutation tests](https://github.com/hasura/graphql-engine-mono/blob/rfc-nonvolatile-functions-mssql/server/tests-py/test_graphql_mutations.py)
|
|
|
|
### Future Work
|
|
|
|
- Upsert feature
|
|
- Nested inserts
|
|
- Mutations for tables without primary keys
|