server: fix one-to-one relationships

GitOrigin-RevId: e19f4dec04abbdcf4589d24031705e5c57ea1fbb
This commit is contained in:
Vladimir Ciobanu 2021-04-27 16:44:51 +03:00 committed by hasura-bot
parent a935746e17
commit f50f61ab6a
5 changed files with 111 additions and 69 deletions

View File

@ -8,6 +8,7 @@
(Add entries below in the order of: server, console, cli, docs, others)
- server: fix regression: `on_conflict` was missing in the schema for inserts in tables where the current user has no columns listed in their update permissions (fix #6804)
- server: fix one-to-one relationship bug (introduced in #459) which prevented adding one-to-one relationships which didn't have the same column name for target and source
- console: fix Postgres table creation when table has a non-lowercase name and a comment (#6760)
- cli: fix regression - `metadata apply —dry-run` was overwriting local metadata files with metadata on server when it should just display the differences.
- cli: add support for `api_limits` metadata object

View File

@ -100,7 +100,7 @@ Create an ``object relationship`` ``details`` on ``author`` *table*, *using* the
"using": {
"foreign_key_constraint_on" : {
"table": "author_details",
"column": "id"
"column": "author_id"
}
}
}

View File

@ -101,7 +101,7 @@ Create an ``object relationship`` ``details`` on ``author`` *table*, *using* the
"using": {
"foreign_key_constraint_on" : {
"table": "author_details",
"column": "id"
"column": "author_id"
}
}
}

View File

@ -28,6 +28,7 @@ import Hasura.RQL.DDL.Deps
import Hasura.RQL.DDL.Permission
import Hasura.RQL.Types
runCreateRelationship
:: forall m b a
. (MonadError QErr m, CacheRWM m, ToJSON a, MetadataM m, Backend b, BackendMetadata b)
@ -143,29 +144,8 @@ objRelP2Setup source qt foreignKeys (RelDef rn ru _) fieldInfoMap = case ru of
`onNothing` throw500 "could not find column info in schema cache"
let nullable = pgiIsNullable colInfo
pure (RelInfo rn ObjRel colMap foreignTable False nullable BeforeParent, dependencies)
RUFKeyOn (RemoteTable remoteTable remoteCol) -> do
foreignTableForeignKeys <- findTable @b remoteTable foreignKeys
ForeignKey constraint _foreignTable colMap <- getRequiredRemoteFkey remoteCol (HS.toList foreignTableForeignKeys)
let dependencies =
[ SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b remoteTable
$ TOForeignKey @b (_cName constraint))
DRRemoteFkey
, SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b qt
$ TOCol @b remoteCol)
DRUsingColumn
, SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITable @b remoteTable)
DRRemoteTable
]
pure (RelInfo rn ObjRel colMap remoteTable False False AfterParent, dependencies)
RUFKeyOn (RemoteTable remoteTable remoteCol) ->
mkFkeyRel ObjRel AfterParent source rn qt remoteTable remoteCol foreignKeys
arrRelP2Setup
:: forall b m
@ -192,34 +172,50 @@ arrRelP2Setup foreignKeys source qt (RelDef rn ru _) = case ru of
$ TOCol @b c)
DRRightColumn)
rCols
pure (RelInfo rn ArrRel (rmColumns rm) refqt True True BeforeParent, deps)
RUFKeyOn (ArrRelUsingFKeyOn refqt refCol) -> do
foreignTableForeignKeys <- findTable @b refqt foreignKeys
let keysThatReferenceUs = filter ((== qt) . _fkForeignTable) (HS.toList foreignTableForeignKeys)
ForeignKey constraint _ colMap <- getRequiredFkey refCol keysThatReferenceUs
let deps = [ SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b refqt
$ TOForeignKey @b (_cName constraint))
DRRemoteFkey
, SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b refqt
$ TOCol @b refCol)
DRUsingColumn
-- we don't need to necessarily track the remote table like we did in
-- case of obj relationships as the remote table is indirectly
-- tracked by tracking the constraint name and 'using_col'
, SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITable @b refqt)
DRRemoteTable
]
mapping = HM.fromList $ map swap $ HM.toList colMap
pure (RelInfo rn ArrRel mapping refqt False False BeforeParent, deps)
pure (RelInfo rn ArrRel (rmColumns rm) refqt True True AfterParent, deps)
RUFKeyOn (ArrRelUsingFKeyOn refqt refCol) ->
mkFkeyRel ArrRel AfterParent source rn qt refqt refCol foreignKeys
mkFkeyRel
:: forall b m
. QErrM m
=> Backend b
=> RelType
-> InsertOrder
-> SourceName
-> RelName
-> TableName b
-> TableName b
-> Column b
-> HashMap (TableName b) (HashSet (ForeignKey b))
-> m (RelInfo b, [SchemaDependency])
mkFkeyRel relType io source rn sourceTable remoteTable remoteColumn foreignKeys = do
foreignTableForeignKeys <- findTable @b remoteTable foreignKeys
let keysThatReferenceUs = filter ((== sourceTable) . _fkForeignTable) (HS.toList foreignTableForeignKeys)
ForeignKey constraint _foreignTable colMap <- getRequiredFkey remoteColumn keysThatReferenceUs
let dependencies =
[ SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b remoteTable
$ TOForeignKey @b (_cName constraint))
DRRemoteFkey
, SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b remoteTable
$ TOCol @b remoteColumn)
DRUsingColumn
, SchemaDependency
(SOSourceObj source
$ AB.mkAnyBackend
$ SOITable @b remoteTable)
DRRemoteTable
]
pure (RelInfo rn relType (reverseHM colMap) remoteTable False False io, dependencies)
where
reverseHM :: Eq y => Hashable y => HashMap x y -> HashMap y x
reverseHM = HM.fromList . fmap swap . HM.toList
purgeRelDep
:: forall b m
@ -266,19 +262,3 @@ getRequiredFkey col fkeys =
"more than one foreign key constraint exists on the given column"
where
filteredFkeys = filter ((== [col]) . HM.keys . _fkColumnMapping) fkeys
getRequiredRemoteFkey
:: QErrM m
=> Backend b
=> Column b
-> [ForeignKey b]
-> m (ForeignKey b)
getRequiredRemoteFkey col fkeys =
case filteredFkeys of
[] -> throw400 ConstraintError
"no foreign constraint exists on the given column"
[k] -> return k
_ -> throw400 ConstraintError
"more than one foreign key constraint exists on the given column"
where
filteredFkeys = filter ((== [col]) . HM.elems . _fkColumnMapping) fkeys

View File

@ -0,0 +1,61 @@
#Create object relationship
- description: Create object relationship using foreign key
url: /v1/query
status: 200
response:
message: success
query:
type: create_object_relationship
args:
table: article
name: author
using:
foreign_key_constraint_on:
table: author
column: author_id
- description: Nested select on article
url: /v1/query
status: 200
response:
- id: 1
title: Article 1
content: Sample article content 1
author:
id: 1
name: Author 1
- id: 2
title: Article 2
content: Sample article content 2
author:
id: 1
name: Author 1
- id: 3
title: Article 3
content: Sample article content 3
author:
id: 2
name: Author 2
query:
type: select
args:
table: article
columns:
- id
- title
- content
- name: author
columns:
- id
- name
- description: Drop object relationship
url: /v1/query
status: 200
response:
message: success
query:
type: drop_relationship
args:
table: article
relationship: author