Fixing issues with SQLite FKs in Schema and Suggest Relationships API Docs

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7729
GitOrigin-RevId: 4ae48019ce71f6ceb3f6d06524302bdd11ca1ed4
This commit is contained in:
Lyndon Maydwell 2023-02-02 21:36:06 +10:00 committed by hasura-bot
parent 69ae616ae5
commit 9a54849985
4 changed files with 89 additions and 23 deletions

View File

@ -62,13 +62,13 @@ function nullableCast(ds: any[]): boolean {
}
const formatTableInfo = (config: Config) => (info: TableInfoInternal): TableInfo => {
const tableName = config.explicit_main_schema ? ["main", info.name] : [info.name];
const ast = sqliteParser(info.sql);
const columnsDdl = getColumnsDdl(ast);
const primaryKeys = ddlPKs(ast);
const foreignKeys = ddlFKs(config, ast);
const foreignKeys = ddlFKs(config, tableName, ast);
const primaryKey = primaryKeys.length > 0 ? { primary_key: primaryKeys } : {};
const foreignKey = foreignKeys.length > 0 ? { foreign_keys: Object.fromEntries(foreignKeys) } : {};
const tableName = config.explicit_main_schema ? ["main", info.name] : [info.name];
return {
name: tableName,
@ -146,7 +146,7 @@ function getColumnsDdl(ddl: any): any[] {
* @param ddl
* @returns [name, FK constraint definition][]
*/
function ddlFKs(config: Config, ddl: any): [string, Constraint][] {
function ddlFKs(config: Config, tableName: Array<string>, ddl: any): [string, Constraint][] {
if(ddl.type != 'statement' || ddl.variant != 'list') {
throw new Error("Encountered a non-statement or non-list DDL for table.");
}
@ -177,7 +177,7 @@ function ddlFKs(config: Config, ddl: any): [string, Constraint][] {
const destinationColumn = definition.references.columns[0];
const foreignTable = config.explicit_main_schema ? ["main", definition.references.name] : [definition.references.name];
return [[
`${sourceColumn.name}->${definition.references.name}.${destinationColumn.name}`,
`${tableName.join('.')}.${sourceColumn.name}->${definition.references.name}.${destinationColumn.name}`,
{ foreign_table: foreignTable,
column_mapping: {
[sourceColumn.name]: destinationColumn.name

View File

@ -408,6 +408,44 @@ X-Hasura-Role: admin
| new_name | true | [RelationshipName](/api-reference/syntax-defs.mdx#relationshipname) | New relationship name |
| source | false | [SourceName](/api-reference/syntax-defs.mdx#sourcename) | Name of the source database of the table (default: `default`) |
## pg_suggest_relationships {#pg-suggest-relationships}
`pg_suggest_relationships` is used to suggest relationships that can be tracked by the `pg_create_*_relationship` API.
An example:
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "pg_suggest_relationships",
"version": 1,
"args": {
"omit_tracked": true,
"source": "chinook",
"tables": [["Artist"]]
}
}
```
### Args syntax {#pg-suggest-relationship-syntax}
| Key | Required | Default | Schema | Description |
| -------- | -------- | -------- | ------------------------------------------------------------------- | ------------------------------------------------------------- |
| source | false | `default` | [SourceName](/api-reference/syntax-defs.mdx#sourcename) | The source to suggest relationships for |
| tables | false | All Tables | [ [TableName](/api-reference/syntax-defs.mdx#tablename) ] | List of tables to consider for suggestions |
| omit_tracked | false | `false` | `Boolean` | Don't re-suggest tracked relationships |
:::info Note
All other source kinds are also supported by using the type `{KIND}_suggest_relationships`.
For example, Snowflake would be: `snowflake_suggest_relationships`, etc.
:::
## mssql_create_object_relationship {#mssql-create-object-relationship}
`create_object_relationship` is used to create an object relationship on
@ -768,3 +806,34 @@ X-Hasura-Role: admin
| name | true | [RelationshipName](/api-reference/syntax-defs.mdx#relationshipname) | The relationship |
| new_name | true | [RelationshipName](/api-reference/syntax-defs.mdx#relationshipname) | New relationship name |
| source | false | [SourceName](/api-reference/syntax-defs.mdx#sourcename) | Name of the source database of the table (default: `default`) |
## mssql_suggest_relationships {#mssql-suggest-relationships}
`mssql_suggest_relationships` is used to suggest relationships that can be tracked by the `mssql_create_*_relationship` API.
An example:
```http
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type": "mssql_suggest_relationships",
"version": 1,
"args": {
"omit_tracked": true,
"source": "chinook",
"tables": [["Artist"]]
}
}
```
### Args syntax {#mssql-suggest-relationship-syntax}
| Key | Required | Default | Schema | Description |
| -------- | -------- | -------- | ------------------------------------------------------------------- | ------------------------------------------------------------- |
| source | false | `default` | [SourceName](/api-reference/syntax-defs.mdx#sourcename) | The source to suggest relationships for |
| tables | false | All Tables | [ [TableName](/api-reference/syntax-defs.mdx#tablename) ] | List of tables to consider for suggestions |
| omit_tracked | false | `false` | `Boolean` | Don't re-suggest tracked relationships |

View File

@ -106,7 +106,7 @@ nameFormatting = NameFormatting id id formatForeignKeyName
-- | Construct foreign key relationship names.
formatForeignKeyName :: Text -> Text
formatForeignKeyName = \case
"Artist" -> "ArtistId->Artist.ArtistId"
"Artist" -> "Album.ArtistId->Artist.ArtistId"
x -> x
chinookFixture :: Fixture ChinookTestEnv

View File

@ -187,8 +187,7 @@ resolveDatabaseMetadata' ::
DC.SourceConfig ->
m (Either QErr (DBObjectsIntrospection 'DataConnector))
resolveDatabaseMetadata' _ DC.SourceConfig {_scSchema = API.SchemaResponse {..}, ..} =
let foreignKeys = fmap API._tiForeignKeys _srTables
tables = Map.fromList $ do
let tables = Map.fromList $ do
API.TableInfo {..} <- _srTables
let primaryKeyColumns = Seq.fromList $ coerce <$> _tiPrimaryKey
let meta =
@ -207,7 +206,7 @@ resolveDatabaseMetadata' _ DC.SourceConfig {_scSchema = API.SchemaResponse {..},
},
_ptmiPrimaryKey = RQL.T.T.PrimaryKey (RQL.T.T.Constraint (DC.ConstraintName "") (OID 0)) <$> NESeq.nonEmptySeq primaryKeyColumns,
_ptmiUniqueConstraints = mempty,
_ptmiForeignKeys = buildForeignKeySet foreignKeys,
_ptmiForeignKeys = buildForeignKeySet _tiForeignKeys,
_ptmiViewInfo =
( if _tiType == API.Table && _tiInsertable && _tiUpdatable && _tiDeletable
then Nothing
@ -228,22 +227,20 @@ resolveDatabaseMetadata' _ DC.SourceConfig {_scSchema = API.SchemaResponse {..},
-- | Construct a 'HashSet' 'RQL.T.T.ForeignKeyMetadata'
-- 'DataConnector' to build the foreign key constraints in the table
-- metadata.
buildForeignKeySet :: [API.ForeignKeys] -> HashSet (RQL.T.T.ForeignKeyMetadata 'DataConnector)
buildForeignKeySet foreignKeys =
buildForeignKeySet :: API.ForeignKeys -> HashSet (RQL.T.T.ForeignKeyMetadata 'DataConnector)
buildForeignKeySet (API.ForeignKeys constraints) =
HashSet.fromList $
join $
foreignKeys <&> \(API.ForeignKeys constraints) ->
constraints & HashMap.foldMapWithKey @[RQL.T.T.ForeignKeyMetadata 'DataConnector]
\constraintName API.Constraint {..} -> maybeToList do
let columnMapAssocList = HashMap.foldrWithKey' (\(API.ColumnName k) (API.ColumnName v) acc -> (DC.ColumnName k, DC.ColumnName v) : acc) [] _cColumnMapping
columnMapping <- NEHashMap.fromList columnMapAssocList
let foreignKey =
RQL.T.T.ForeignKey
{ _fkConstraint = RQL.T.T.Constraint (Witch.from constraintName) (OID 1),
_fkForeignTable = Witch.from _cForeignTable,
_fkColumnMapping = columnMapping
}
pure $ RQL.T.T.ForeignKeyMetadata foreignKey
constraints & HashMap.foldMapWithKey @[RQL.T.T.ForeignKeyMetadata 'DataConnector]
\constraintName API.Constraint {..} -> maybeToList do
let columnMapAssocList = HashMap.foldrWithKey' (\(API.ColumnName k) (API.ColumnName v) acc -> (DC.ColumnName k, DC.ColumnName v) : acc) [] _cColumnMapping
columnMapping <- NEHashMap.fromList columnMapAssocList
let foreignKey =
RQL.T.T.ForeignKey
{ _fkConstraint = RQL.T.T.Constraint (Witch.from constraintName) (OID 1),
_fkForeignTable = Witch.from _cForeignTable,
_fkColumnMapping = columnMapping
}
pure $ RQL.T.T.ForeignKeyMetadata foreignKey
-- | This is needed to get permissions to work
parseBoolExpOperations' ::