dont set non-null constraint for manual object relationships (close #462)

This commit is contained in:
nizar-m 2018-09-18 17:01:16 +05:30 committed by Shahidh K Muhammed
parent 85df9ac1e8
commit cde559fe58
8 changed files with 81 additions and 38 deletions

View File

@ -99,7 +99,7 @@ isValidTableName = isValidName . qualTableToName
isValidField :: FieldInfo -> Bool
isValidField = \case
FIColumn (PGColInfo col _ _) -> isColEligible col
FIRelationship (RelInfo rn _ _ remTab _) -> isRelEligible rn remTab
FIRelationship (RelInfo rn _ _ remTab _ _) -> isRelEligible rn remTab
where
isColEligible = isValidName . G.Name . getPGColTxt
isRelEligible rn rt = isValidName (G.Name $ getRelTxt rn)
@ -262,7 +262,7 @@ object_relationship: remote_table
-}
mkRelFld :: RelInfo -> Bool -> ObjFldInfo
mkRelFld (RelInfo rn rTy _ remTab _) isNullable = case rTy of
mkRelFld (RelInfo rn rTy _ remTab _ isManual) isNullable = case rTy of
ArrRel ->
ObjFldInfo (Just "An array relationship") (G.Name $ getRelTxt rn)
(fromInpValL $ mkSelArgs remTab)
@ -272,7 +272,8 @@ mkRelFld (RelInfo rn rTy _ remTab _) isNullable = case rTy of
Map.empty
objRelTy
where
objRelTy = bool (G.toGT $ G.toNT relTabTy) (G.toGT relTabTy) isNullable
objRelTy = bool (G.toGT $ G.toNT relTabTy) (G.toGT relTabTy) isObjRelNullable
isObjRelNullable = isManual || isNullable
relTabTy = mkTableTy remTab
{-
@ -400,7 +401,7 @@ mkBoolExpInp tn fields =
mkFldExpInp = \case
Left (PGColInfo colName colTy _) ->
mk (G.Name $ getPGColTxt colName) (mkCompExpTy colTy)
Right (RelInfo relName _ _ remTab _, _, _, _) ->
Right (RelInfo relName _ _ remTab _ _, _, _, _) ->
mk (G.Name $ getRelTxt relName) (mkBoolExpTy remTab)
mkPGColInp :: PGColInfo -> InpValInfo

View File

@ -178,7 +178,7 @@ objRelP2Setup qt (RelDef rn ru _) = do
(lCols, rCols) = unzip $ M.toList $ rmColumns rm
deps = map (\c -> SchemaDependency (SOTableObj qt $ TOCol c) "lcol") lCols
<> map (\c -> SchemaDependency (SOTableObj refqt $ TOCol c) "rcol") rCols
return $ RelInfo rn ObjRel (zip lCols rCols) refqt deps
return $ RelInfo rn ObjRel (zip lCols rCols) refqt deps True
RUFKeyOn cn -> do
res <- liftTx $ Q.catchE defaultTxErrorHandler $ fetchFKeyDetail cn
case mapMaybe processRes res of
@ -190,7 +190,7 @@ objRelP2Setup qt (RelDef rn ru _) = do
]
refqt = QualifiedTable refsn reftn
void $ askTabInfo refqt
return $ RelInfo rn ObjRel colMapping refqt deps
return $ RelInfo rn ObjRel colMapping refqt deps False
_ -> throw400 ConstraintError
"more than one foreign key constraint exists on the given column"
addFldToCache (fromRel rn) (FIRelationship relInfo) qt
@ -273,7 +273,7 @@ arrRelP2Setup qt (RelDef rn ru _) = do
(lCols, rCols) = unzip $ M.toList $ rmColumns rm
deps = map (\c -> SchemaDependency (SOTableObj qt $ TOCol c) "lcol") lCols
<> map (\c -> SchemaDependency (SOTableObj refqt $ TOCol c) "rcol") rCols
return $ RelInfo rn ArrRel (zip lCols rCols) refqt deps
return $ RelInfo rn ArrRel (zip lCols rCols) refqt deps True
RUFKeyOn (ArrRelUsingFKeyOn refqt refCol) -> do
let QualifiedTable refSn refTn = refqt
res <- liftTx $ Q.catchE defaultTxErrorHandler $
@ -285,7 +285,7 @@ arrRelP2Setup qt (RelDef rn ru _) = do
let deps = [ SchemaDependency (SOTableObj refqt $ TOCons consName) "remote_fkey"
, SchemaDependency (SOTableObj refqt $ TOCol refCol) "using_col"
]
return $ RelInfo rn ArrRel (map swap mapping) refqt deps
return $ RelInfo rn ArrRel (map swap mapping) refqt deps False
_ -> throw400 ConstraintError
"more than one foreign key constraint exists on the given column"
addFldToCache (fromRel rn) (FIRelationship relInfo) qt

View File

@ -90,7 +90,7 @@ convSelCol fieldInfoMap _ (SCExtRel rn malias selQ) = do
let pgWhenRelErr = "only relationships can be expanded"
relInfo <- withPathK "name" $
askRelType fieldInfoMap rn pgWhenRelErr
let (RelInfo _ _ _ relTab _) = relInfo
let (RelInfo _ _ _ relTab _ _) = relInfo
(rfim, rspi) <- fetchRelDet rn relTab
resolvedSelQ <- resolveStar rfim rspi selQ
return [ECRel rn malias resolvedSelQ]
@ -345,7 +345,7 @@ convExtRel fieldInfoMap relName mAlias selQ prepValBuilder = do
-- Point to the name key
relInfo <- withPathK "name" $
askRelType fieldInfoMap relName pgWhenRelErr
let (RelInfo _ relTy colMapping relTab _) = relInfo
let (RelInfo _ relTy colMapping relTab _ _) = relInfo
(relCIM, relSPI) <- fetchRelDet relName relTab
selectData <- case relTy of
ObjRel ->

View File

@ -372,7 +372,7 @@ convColRhs bExpBuilder tableQual annVal = case annVal of
-- And them all
return $ AVCol pci $ foldr (S.BEBin S.AndOp) (S.BELit True) bExps
AVRel ri@(RelInfo _ _ colMapping relTN _) nesAnn fltr -> do
AVRel ri@(RelInfo _ _ colMapping relTN _ _) nesAnn fltr -> do
-- Convert the where clause on the relationship
annRelBoolExp <- convBoolRhs bExpBuilder (S.mkQual relTN) nesAnn
let backCompExp = foldr (S.BEBin S.AndOp) (S.BELit True) $
@ -393,7 +393,7 @@ cColExp
-> S.BoolExp
cColExp annVal = case annVal of
AVCol _ be -> be
AVRel (RelInfo _ _ _ relTN _) nesAnn backCompExp -> do
AVRel (RelInfo _ _ _ relTN _ _) nesAnn backCompExp -> do
-- Convert the where clause on the relationship
let annRelBoolExp = cBoolExp nesAnn
innerBoolExp = S.BEBin S.AndOp backCompExp annRelBoolExp

View File

@ -210,11 +210,12 @@ getColInfos cols allColInfos = flip filter allColInfos $ \ci ->
data RelInfo
= RelInfo
{ riName :: !RelName
, riType :: !RelType
, riMapping :: ![(PGCol, PGCol)]
, riRTable :: !QualifiedTable
, riDeps :: ![SchemaDependency]
{ riName :: !RelName
, riType :: !RelType
, riMapping :: ![(PGCol, PGCol)]
, riRTable :: !QualifiedTable
, riDeps :: ![SchemaDependency]
, riIsManual :: !Bool
} deriving (Show, Eq)
$(deriveToJSON (aesonDrop 2 snakeCase) ''RelInfo)

View File

@ -22,8 +22,8 @@ args:
id SERIAL PRIMARY KEY,
title TEXT,
content TEXT,
author_id INTEGER REFERENCES author(id),
is_published BOOLEAN,
author_id INTEGER NOT NULL REFERENCES author(id),
is_published BOOLEAN NOT NULL default FALSE,
published_on TIMESTAMP
)
- type: track_table
@ -34,11 +34,24 @@ args:
#Object relationship
- type: create_object_relationship
args:
name: author_obj_rel_fk
table: article
name: author
using:
foreign_key_constraint_on: author_id
#Object relationship
- type: create_object_relationship
args:
name: author_obj_rel_manual
table: article
using:
manual_configuration:
remote_table:
schema: public
name: author
column_mapping:
author_id: id
#Array relationship
- type: create_array_relationship
args:
@ -55,7 +68,10 @@ args:
table: article
role: user
permission:
columns: '*'
columns:
- id
- title
- content
filter:
$or:
- author_id: X-HASURA-USER-ID
@ -76,7 +92,8 @@ args:
table: author
role: user
permission:
columns: '*'
columns:
- name
filter:
id: X-HASURA-USER-ID

View File

@ -0,0 +1,40 @@
import pytest
import yaml
from validate import check_query_f
class TestGraphqlIntrospection:
def test_introspection(self, hge_ctx):
with open(self.dir + "/introspection.yaml") as c:
conf = yaml.load(c)
code, resp = hge_ctx.anyq( conf['url'], conf['query'], {})
assert code == 200
hasArticle = False
hasArticleAuthorFKRel = False
hasArticleAuthorManualRel = False
for t in resp['data']['__schema']['types']:
if t['name'] == 'article':
hasArticle = True
for fld in t['fields']:
if fld['name'] == 'author_obj_rel_manual':
hasArticleAuthorManualRel = True
assert fld['type']['kind'] == 'OBJECT'
elif fld['name'] == 'author_obj_rel_fk':
hasArticleAuthorFKRel = True
assert fld['type']['kind'] == 'NON_NULL'
assert hasArticle
assert hasArticleAuthorFKRel
assert hasArticleAuthorManualRel
def test_introspection_user(self, hge_ctx):
check_query_f(hge_ctx, self.dir + "/introspection_user_role.yaml")
@pytest.fixture(autouse=True)
def transact(self, request, hge_ctx):
self.dir = "queries/graphql_introspection"
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
assert st_code == 200, resp
yield
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
assert st_code == 200, resp

View File

@ -210,19 +210,3 @@ class TestGraphqlDelete:
assert st_code == 200, resp
class TestGraphqlIntrospection:
def test_introspection(self, hge_ctx):
check_query_f(hge_ctx, self.dir + "/introspection.yaml")
def test_introspection_user(self, hge_ctx):
check_query_f(hge_ctx, self.dir + "/introspection_user_role.yaml")
@pytest.fixture(autouse=True)
def transact(self, request, hge_ctx):
self.dir = "queries/graphql_introspection"
st_code, resp = hge_ctx.v1q_f(self.dir + '/setup.yaml')
assert st_code == 200, resp
yield
st_code, resp = hge_ctx.v1q_f(self.dir + '/teardown.yaml')
assert st_code == 200, resp