From db9f137c6761152325f93f4d92e0ec69df43b3f4 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Wed, 19 Jun 2019 14:58:16 +0530 Subject: [PATCH 01/12] Add Postgres comments to table descriptions --- server/src-exec/Migrate.hs | 11 ++- server/src-lib/Hasura/GraphQL/Schema.hs | 26 ++++-- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 6 +- .../src-lib/Hasura/RQL/Types/SchemaCache.hs | 4 +- server/src-rsr/catalog_metadata.sql | 1 + server/src-rsr/initialise.sql | 13 +++ server/src-rsr/migrate_from_17_to_18.sql | 90 +++++++++++++++++++ 7 files changed, 136 insertions(+), 15 deletions(-) create mode 100644 server/src-rsr/migrate_from_17_to_18.sql diff --git a/server/src-exec/Migrate.hs b/server/src-exec/Migrate.hs index 619446b0b656d..5273739e8ce1f 100644 --- a/server/src-exec/Migrate.hs +++ b/server/src-exec/Migrate.hs @@ -19,7 +19,7 @@ import qualified Data.Yaml.TH as Y import qualified Database.PG.Query as Q curCatalogVer :: T.Text -curCatalogVer = "17" +curCatalogVer = "18" migrateMetadata :: ( MonadTx m @@ -327,6 +327,10 @@ from16To17 = AND table_name = 'hdb_allowlist'; |] +from17To18 :: MonadTx m => m () +from17To18 = liftTx $ Q.multiQE defaultTxErrorHandler + $(Q.sqlFromFile "src-rsr/migrate_from_17_to_18.sql") + migrateCatalog :: ( MonadTx m , CacheRWM m @@ -358,10 +362,13 @@ migrateCatalog migrationTime = do | preVer == "14" -> from14ToCurrent | preVer == "15" -> from15ToCurrent | preVer == "16" -> from16ToCurrent + | preVer == "17" -> from17ToCurrent | otherwise -> throw400 NotSupported $ "unsupported version : " <> preVer where - from16ToCurrent = from16To17 >> postMigrate + from17ToCurrent = from17To18 >> postMigrate + + from16ToCurrent = from16To17 >> from17ToCurrent from15ToCurrent = from15To16 >> from16ToCurrent diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 541ae1fd82b67..12e9b5644adc8 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -262,15 +262,20 @@ type table { -} mkTableObj :: QualifiedTable + -> Maybe Text -> [SelField] -> ObjTyInfo -mkTableObj tn allowedFlds = +mkTableObj tn descM allowedFlds = mkObjTyInfo (Just desc) (mkTableTy tn) Set.empty (mapFromL _fiName flds) HasuraType where flds = concatMap (either (pure . mkPGColFld) mkRelFld') allowedFlds mkRelFld' (relInfo, allowAgg, _, _, isNullable) = mkRelFld allowAgg relInfo isNullable - desc = G.Description $ "columns and relationships of " <>> tn + defaultDesc = "columns and relationships of " <>> tn + desc = G.Description $ case descM of + Nothing -> defaultDesc + Just "" -> defaultDesc + Just d -> d <> "\n\n" <> defaultDesc {- type table_aggregate { @@ -1228,6 +1233,8 @@ mkOnConflictTypes tn uniqueOrPrimaryCons cols = mkGCtxRole' :: QualifiedTable + -- table description + -> Maybe Text -- insert permission -> Maybe ([PGColInfo], RelationInfoMap) -- select permission @@ -1244,7 +1251,7 @@ mkGCtxRole' -- all functions -> [FunctionInfo] -> TyAgg -mkGCtxRole' tn insPermM selPermM updColsM +mkGCtxRole' tn descM insPermM selPermM updColsM delPermM pkeyCols constraints viM funcs = TyAgg (mkTyInfoMap allTypes) fieldMap scalars ordByCtx @@ -1356,7 +1363,7 @@ mkGCtxRole' tn insPermM selPermM updColsM && any (`isMutable` viM) [viIsInsertable, viIsUpdatable, viIsDeletable] -- table obj - selObjM = mkTableObj tn <$> selFldsM + selObjM = mkTableObj tn descM <$> selFldsM -- aggregate objs and order by inputs (aggObjs, aggOrdByInps) = case selPermM of @@ -1574,6 +1581,7 @@ mkGCtxRole :: (MonadError QErr m) => TableCache -> QualifiedTable + -> Maybe Text -> FieldInfoMap -> [PGCol] -> [ConstraintName] @@ -1582,7 +1590,7 @@ mkGCtxRole -> RoleName -> RolePermInfo -> m (TyAgg, RootFlds, InsCtxMap) -mkGCtxRole tableCache tn fields pCols constraints funcs viM role permInfo = do +mkGCtxRole tableCache tn descM fields pCols constraints funcs viM role permInfo = do selPermM <- mapM (getSelPerm tableCache fields role) $ _permSel permInfo tabInsInfoM <- forM (_permIns permInfo) $ \ipi -> do ctx <- mkInsCtx role tableCache fields ipi $ _permUpd permInfo @@ -1592,7 +1600,7 @@ mkGCtxRole tableCache tn fields pCols constraints funcs viM role permInfo = do let insPermM = snd <$> tabInsInfoM insCtxM = fst <$> tabInsInfoM updColsM = filterColInfos . upiCols <$> _permUpd permInfo - tyAgg = mkGCtxRole' tn insPermM selPermM updColsM + tyAgg = mkGCtxRole' tn descM insPermM selPermM updColsM (void $ _permDel permInfo) pColInfos constraints viM funcs rootFlds = getRootFldsRole tn pCols constraints fields funcs viM permInfo insCtxMap = maybe Map.empty (Map.singleton tn) insCtxM @@ -1638,15 +1646,15 @@ mkGCtxMapTable -> m (Map.HashMap RoleName (TyAgg, RootFlds, InsCtxMap)) mkGCtxMapTable tableCache funcCache tabInfo = do m <- Map.traverseWithKey - (mkGCtxRole tableCache tn fields pkeyCols validConstraints tabFuncs viewInfo) rolePerms + (mkGCtxRole tableCache tn descM fields pkeyCols validConstraints tabFuncs viewInfo) rolePerms adminInsCtx <- mkAdminInsCtx tn tableCache fields - let adminCtx = mkGCtxRole' tn (Just (colInfos, icRelations adminInsCtx)) + let adminCtx = mkGCtxRole' tn descM (Just (colInfos, icRelations adminInsCtx)) (Just (True, selFlds)) (Just colInfos) (Just ()) pkeyColInfos validConstraints viewInfo tabFuncs adminInsCtxMap = Map.singleton tn adminInsCtx return $ Map.insert adminRole (adminCtx, adminRootFlds, adminInsCtxMap) m where - TableInfo tn _ fields rolePerms constraints pkeyCols viewInfo _ = tabInfo + TableInfo tn descM _ fields rolePerms constraints pkeyCols viewInfo _ = tabInfo validConstraints = mkValidConstraints constraints colInfos = getValidCols fields validColNames = map pgiName colInfos diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index 84b28d9ea5cbf..8759fab03dcf7 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -85,15 +85,15 @@ trackExistingTableOrViewP2 vn isSystemDefined = do return successMsg where QualifiedObject sn tn = vn - mkTableInfo (cols, pCols, constraints, viewInfoM) = + mkTableInfo (cols, pCols, constraints, viewInfoM, descM) = let colMap = M.fromList $ flip map (Q.getAltJ cols) $ \c -> (fromPGCol $ pgiName c, FIColumn c) - in TableInfo vn isSystemDefined colMap mempty (Q.getAltJ constraints) + in TableInfo vn descM isSystemDefined colMap mempty (Q.getAltJ constraints) (Q.getAltJ pCols) (Q.getAltJ viewInfoM) mempty fetchTableCatalog = map mkTableInfo <$> Q.listQE defaultTxErrorHandler [Q.sql| SELECT columns, primary_key_columns, - constraints, view_info + constraints, view_info, description FROM hdb_catalog.hdb_table_info_agg WHERE table_schema = $1 AND table_name = $2 |] (sn, tn) True diff --git a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs index 9abf5a8dae47e..660b88cb12bf6 100644 --- a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs +++ b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs @@ -343,6 +343,7 @@ mutableView qt f mVI operation = data TableInfo = TableInfo { tiName :: !QualifiedTable + , tiDescription :: !(Maybe Text) , tiSystemDefined :: !Bool , tiFieldInfoMap :: !FieldInfoMap , tiRolePermInfoMap :: !RolePermInfoMap @@ -357,6 +358,7 @@ $(deriveToJSON (aesonDrop 2 snakeCase) ''TableInfo) instance FromJSON TableInfo where parseJSON = withObject "TableInfo" $ \o -> do name <- o .: "name" + description <- o .:? "description" columns <- o .: "columns" pkeyCols <- o .: "primary_key_columns" constraints <- o .: "constraints" @@ -364,7 +366,7 @@ instance FromJSON TableInfo where isSystemDefined <- o .:? "is_system_defined" .!= False let colMap = M.fromList $ flip map columns $ \c -> (fromPGCol $ pgiName c, FIColumn c) - return $ TableInfo name isSystemDefined colMap mempty + return $ TableInfo name description isSystemDefined colMap mempty constraints pkeyCols viewInfoM mempty data FunctionType diff --git a/server/src-rsr/catalog_metadata.sql b/server/src-rsr/catalog_metadata.sql index d08976a4a57f2..683a3b6d81fe6 100644 --- a/server/src-rsr/catalog_metadata.sql +++ b/server/src-rsr/catalog_metadata.sql @@ -36,6 +36,7 @@ from 'schema', table_schema, 'name', table_name ), + 'description', description, 'columns', columns, 'primary_key_columns', primary_key_columns, 'constraints', constraints, diff --git a/server/src-rsr/initialise.sql b/server/src-rsr/initialise.sql index 5bad136224575..99b5ebb8fe39d 100644 --- a/server/src-rsr/initialise.sql +++ b/server/src-rsr/initialise.sql @@ -440,6 +440,7 @@ CREATE VIEW hdb_catalog.hdb_table_info_agg AS ( select tables.table_name as table_name, tables.table_schema as table_schema, + descriptions.description, coalesce(columns.columns, '[]') as columns, coalesce(pk.columns, '[]') as primary_key_columns, coalesce(constraints.constraints, '[]') as constraints, @@ -510,6 +511,18 @@ from tables.table_schema = views.table_schema AND tables.table_name = views.table_name ) + left outer join ( + select + pc.relname as table_name, + pn.nspname as table_schema, + pd.description + from pg_class pc + left join pg_namespace pn on pn.oid = pc.relnamespace + left join pg_description pd on pd.objoid = pc.oid + ) descriptions on ( + tables.table_schema = descriptions.table_schema + AND tables.table_name = descriptions.table_name + ) ); CREATE VIEW hdb_catalog.hdb_function_info_agg AS ( diff --git a/server/src-rsr/migrate_from_17_to_18.sql b/server/src-rsr/migrate_from_17_to_18.sql new file mode 100644 index 0000000000000..413a9ce8e6011 --- /dev/null +++ b/server/src-rsr/migrate_from_17_to_18.sql @@ -0,0 +1,90 @@ +DROP VIEW hdb_catalog.hdb_table_info_agg; + +CREATE VIEW hdb_catalog.hdb_table_info_agg AS ( +select + tables.table_name as table_name, + tables.table_schema as table_schema, + descriptions.description, + coalesce(columns.columns, '[]') as columns, + coalesce(pk.columns, '[]') as primary_key_columns, + coalesce(constraints.constraints, '[]') as constraints, + coalesce(views.view_info, 'null') as view_info +from + information_schema.tables as tables + left outer join ( + select + c.table_name, + c.table_schema, + json_agg( + json_build_object( + 'name', + column_name, + 'type', + udt_name, + 'is_nullable', + is_nullable :: boolean + ) + ) as columns + from + information_schema.columns c + group by + c.table_schema, + c.table_name + ) columns on ( + tables.table_schema = columns.table_schema + AND tables.table_name = columns.table_name + ) + left outer join ( + select * from hdb_catalog.hdb_primary_key + ) pk on ( + tables.table_schema = pk.table_schema + AND tables.table_name = pk.table_name + ) + left outer join ( + select + c.table_schema, + c.table_name, + json_agg(constraint_name) as constraints + from + information_schema.table_constraints c + where + c.constraint_type = 'UNIQUE' + or c.constraint_type = 'PRIMARY KEY' + group by + c.table_schema, + c.table_name + ) constraints on ( + tables.table_schema = constraints.table_schema + AND tables.table_name = constraints.table_name + ) + left outer join ( + select + table_schema, + table_name, + json_build_object( + 'is_updatable', + (is_updatable::boolean OR is_trigger_updatable::boolean), + 'is_deletable', + (is_updatable::boolean OR is_trigger_deletable::boolean), + 'is_insertable', + (is_insertable_into::boolean OR is_trigger_insertable_into::boolean) + ) as view_info + from + information_schema.views v + ) views on ( + tables.table_schema = views.table_schema + AND tables.table_name = views.table_name + ) + left outer join ( + select + pc.relname as table_name, + pn.nspname as table_schema, + pd.description + from pg_class pc + left join pg_namespace pn on pn.oid = pc.relnamespace + left join pg_description pd on pd.objoid = pc.oid + ) descriptions on ( + tables.table_schema = descriptions.table_schema + AND tables.table_name = descriptions.table_name + ) +); From e1a9bd0937595b2353246be85794370096c8bca0 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Fri, 21 Jun 2019 13:30:57 +0530 Subject: [PATCH 02/12] Create newtype for PGDescription --- server/src-lib/Hasura/GraphQL/Schema.hs | 19 ++++++++++--------- .../src-lib/Hasura/RQL/Types/SchemaCache.hs | 6 +++--- server/src-lib/Hasura/SQL/Types.hs | 4 ++++ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 12e9b5644adc8..197218c7b00c2 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -262,20 +262,21 @@ type table { -} mkTableObj :: QualifiedTable - -> Maybe Text + -> Maybe PGDescription -> [SelField] -> ObjTyInfo mkTableObj tn descM allowedFlds = - mkObjTyInfo (Just desc) (mkTableTy tn) Set.empty (mapFromL _fiName flds) HasuraType + mkObjTyInfo (Just gqlDesc) (mkTableTy tn) Set.empty (mapFromL _fiName flds) HasuraType where flds = concatMap (either (pure . mkPGColFld) mkRelFld') allowedFlds mkRelFld' (relInfo, allowAgg, _, _, isNullable) = mkRelFld allowAgg relInfo isNullable - defaultDesc = "columns and relationships of " <>> tn - desc = G.Description $ case descM of - Nothing -> defaultDesc - Just "" -> defaultDesc - Just d -> d <> "\n\n" <> defaultDesc + txtDescDefault = "columns and relationships of " <>> tn + gqlDesc = G.Description $ case descM of + Nothing -> txtDescDefault + Just (PGDescription txtDesc) -> if T.length txtDesc == 0 + then txtDescDefault + else txtDesc <> "\n\n" <> txtDescDefault {- type table_aggregate { @@ -1234,7 +1235,7 @@ mkOnConflictTypes tn uniqueOrPrimaryCons cols = mkGCtxRole' :: QualifiedTable -- table description - -> Maybe Text + -> Maybe PGDescription -- insert permission -> Maybe ([PGColInfo], RelationInfoMap) -- select permission @@ -1581,7 +1582,7 @@ mkGCtxRole :: (MonadError QErr m) => TableCache -> QualifiedTable - -> Maybe Text + -> Maybe PGDescription -> FieldInfoMap -> [PGCol] -> [ConstraintName] diff --git a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs index 660b88cb12bf6..c948400c760c6 100644 --- a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs +++ b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs @@ -343,7 +343,7 @@ mutableView qt f mVI operation = data TableInfo = TableInfo { tiName :: !QualifiedTable - , tiDescription :: !(Maybe Text) + , tiDescription :: !(Maybe PGDescription) , tiSystemDefined :: !Bool , tiFieldInfoMap :: !FieldInfoMap , tiRolePermInfoMap :: !RolePermInfoMap @@ -358,7 +358,7 @@ $(deriveToJSON (aesonDrop 2 snakeCase) ''TableInfo) instance FromJSON TableInfo where parseJSON = withObject "TableInfo" $ \o -> do name <- o .: "name" - description <- o .:? "description" + descM <- o .:? "description" columns <- o .: "columns" pkeyCols <- o .: "primary_key_columns" constraints <- o .: "constraints" @@ -366,7 +366,7 @@ instance FromJSON TableInfo where isSystemDefined <- o .:? "is_system_defined" .!= False let colMap = M.fromList $ flip map columns $ \c -> (fromPGCol $ pgiName c, FIColumn c) - return $ TableInfo name description isSystemDefined colMap mempty + return $ TableInfo name descM isSystemDefined colMap mempty constraints pkeyCols viewInfoM mempty data FunctionType diff --git a/server/src-lib/Hasura/SQL/Types.hs b/server/src-lib/Hasura/SQL/Types.hs index ad9e3d3d47536..50d31d8f2eada 100644 --- a/server/src-lib/Hasura/SQL/Types.hs +++ b/server/src-lib/Hasura/SQL/Types.hs @@ -226,6 +226,10 @@ snakeCaseTable (QualifiedObject sn tn) = type QualifiedFunction = QualifiedObject FunctionName +newtype PGDescription + = PGDescription { getPGDescription :: T.Text } + deriving (Show, Eq, FromJSON, ToJSON, Q.FromCol) + newtype PGCol = PGCol { getPGColTxt :: T.Text } deriving (Show, Eq, Ord, FromJSON, ToJSON, Hashable, Q.ToPrepArg, Q.FromCol, ToJSONKey, FromJSONKey, Lift) From 4a9a26110ed8c6816d7cee28d77ae34d4f9474c1 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Thu, 11 Jul 2019 17:15:48 +0530 Subject: [PATCH 03/12] update cache on change in comment --- server/src-lib/Hasura/GraphQL/Schema.hs | 4 +--- server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs | 12 ++++++++---- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 15 ++++++++++----- server/src-rsr/table_meta.sql | 5 ++++- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 197218c7b00c2..989e2596c4055 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -274,9 +274,7 @@ mkTableObj tn descM allowedFlds = txtDescDefault = "columns and relationships of " <>> tn gqlDesc = G.Description $ case descM of Nothing -> txtDescDefault - Just (PGDescription txtDesc) -> if T.length txtDesc == 0 - then txtDescDefault - else txtDesc <> "\n\n" <> txtDescDefault + Just (PGDescription txtDesc) -> T.unlines [txtDesc, txtDescDefault] {- type table_aggregate { diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs index 701351d842be2..e6869a0415e34 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs @@ -59,6 +59,7 @@ data TableMeta = TableMeta { tmOid :: !Int , tmTable :: !QualifiedTable + , tmDescription :: !(Maybe PGDescription) , tmColumns :: ![PGColMeta] , tmConstraints :: ![ConstraintMeta] , tmForeignKeys :: ![ForeignKey] @@ -67,8 +68,8 @@ data TableMeta fetchTableMeta :: Q.Tx [TableMeta] fetchTableMeta = do res <- Q.listQ $(Q.sqlFromFile "src-rsr/table_meta.sql") () False - forM res $ \(ts, tn, toid, cols, constrnts, fkeys) -> - return $ TableMeta toid (QualifiedObject ts tn) (Q.getAltJ cols) + forM res $ \(ts, tn, toid, descM, cols, constrnts, fkeys) -> + return $ TableMeta toid (QualifiedObject ts tn) descM (Q.getAltJ cols) (Q.getAltJ constrnts) (Q.getAltJ fkeys) getOverlap :: (Eq k, Hashable k) => (v -> k) -> [v] -> [v] -> [(v, v)] @@ -94,12 +95,13 @@ data TableDiff -- used for generating types on_conflict clauses -- TODO: this ideally should't be part of TableDiff , _tdUniqOrPriCons :: ![ConstraintName] + , _tdNewDescription :: !(Maybe PGDescription) } deriving (Show, Eq) getTableDiff :: TableMeta -> TableMeta -> TableDiff getTableDiff oldtm newtm = TableDiff mNewName droppedCols addedCols alteredCols - droppedFKeyConstraints uniqueOrPrimaryCons + droppedFKeyConstraints uniqueOrPrimaryCons mNewDesc where mNewName = bool (Just $ tmTable newtm) Nothing $ tmTable oldtm == tmTable newtm oldCols = tmColumns oldtm @@ -108,6 +110,8 @@ getTableDiff oldtm newtm = uniqueOrPrimaryCons = [cmName cm | cm <- tmConstraints newtm, isUniqueOrPrimary (cmType cm)] + mNewDesc = tmDescription newtm + droppedCols = map pcmColumnName $ getDifference pcmOrdinalPosition oldCols newCols @@ -151,7 +155,7 @@ getTableChangeDeps ti tableDiff = do return $ droppedConsDeps <> droppedColDeps where tn = tiName ti - TableDiff _ droppedCols _ _ droppedFKeyConstraints _ = tableDiff + TableDiff _ droppedCols _ _ droppedFKeyConstraints _ _ = tableDiff data SchemaDiff = SchemaDiff diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index 8759fab03dcf7..f5c0415597930 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -143,6 +143,8 @@ processTableChanges ti tableDiff = do withOldTabName = do -- replace constraints replaceConstraints tn + -- replace description + replaceDescription tn -- for all the dropped columns procDroppedCols tn -- for all added columns @@ -163,10 +165,13 @@ processTableChanges ti tableDiff = do maybe withOldTabName withNewTabName mNewName where - TableDiff mNewName droppedCols addedCols alteredCols _ constraints = tableDiff + TableDiff mNewName droppedCols addedCols alteredCols _ constraints descM = tableDiff replaceConstraints tn = flip modTableInCache tn $ \tInfo -> return $ tInfo {tiUniqOrPrimConstraints = constraints} + replaceDescription tn = flip modTableInCache tn $ \tInfo -> + return $ tInfo {tiDescription = descM} + procDroppedCols tn = forM_ droppedCols $ \droppedCol -> -- Drop the column from the cache @@ -606,18 +611,18 @@ execWithMDCheck (RunSQL t cascade _) = do where reportFuncs = T.intercalate ", " . map dquoteTxt -isAltrDropReplace :: QErrM m => T.Text -> m Bool -isAltrDropReplace = either throwErr return . matchRegex regex False +isAltrDropReplaceComment :: QErrM m => T.Text -> m Bool +isAltrDropReplaceComment = either throwErr return . matchRegex regex False where throwErr s = throw500 $ "compiling regex failed: " <> T.pack s - regex = "alter|drop|replace|create function" + regex = "alter|drop|replace|create function|comment on" runRunSQL :: (QErrM m, UserInfoM m, CacheRWM m, MonadTx m, MonadIO m, HasHttpManager m, HasSQLGenCtx m) => RunSQL -> m EncJSON runRunSQL q@(RunSQL t _ mChkMDCnstcy) = do adminOnly - isMDChkNeeded <- maybe (isAltrDropReplace t) return mChkMDCnstcy + isMDChkNeeded <- maybe (isAltrDropReplaceComment t) return mChkMDCnstcy bool (execRawSQL t) (execWithMDCheck q) isMDChkNeeded -- Should be used only after checking the status diff --git a/server/src-rsr/table_meta.sql b/server/src-rsr/table_meta.sql index b6c539c929177..7d85313da2532 100644 --- a/server/src-rsr/table_meta.sql +++ b/server/src-rsr/table_meta.sql @@ -2,6 +2,7 @@ SELECT t.table_schema, t.table_name, t.table_oid, + t.description, coalesce(c.columns, '[]') as columns, coalesce(f.constraints, '[]') as constraints, coalesce(fk.fkeys, '[]') as foreign_keys @@ -10,10 +11,12 @@ FROM SELECT c.oid as table_oid, c.relname as table_name, - n.nspname as table_schema + n.nspname as table_schema, + pd.description as description FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace as n ON c.relnamespace = n.oid + LEFT JOIN pg_catalog.pg_description pd on c.oid = pd.objoid ) t LEFT OUTER JOIN ( SELECT From ac8f9b12430b84fe9a1542f873b1c780ac6e3721 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Thu, 11 Jul 2019 18:38:02 +0530 Subject: [PATCH 04/12] move table comments in API explorer --- server/src-lib/Hasura/GraphQL/Schema.hs | 94 ++++++++++--------- .../src-lib/Hasura/RQL/DDL/Schema/Function.hs | 7 +- .../src-lib/Hasura/RQL/Types/SchemaCache.hs | 1 + 3 files changed, 57 insertions(+), 45 deletions(-) diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 989e2596c4055..6e725d7124231 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -124,6 +124,11 @@ compAggOps = ["max", "min"] isAggFld :: G.Name -> Bool isAggFld = flip elem (numAggOps <> compAggOps) +mkDescription :: Maybe PGDescription -> Text -> G.Description +mkDescription descM defaultTxt = G.Description $ case descM of + Nothing -> defaultTxt + Just (PGDescription descTxt) -> T.unlines [descTxt, defaultTxt] + mkColName :: PGCol -> G.Name mkColName (PGCol n) = G.Name n @@ -262,19 +267,15 @@ type table { -} mkTableObj :: QualifiedTable - -> Maybe PGDescription -> [SelField] -> ObjTyInfo -mkTableObj tn descM allowedFlds = - mkObjTyInfo (Just gqlDesc) (mkTableTy tn) Set.empty (mapFromL _fiName flds) HasuraType +mkTableObj tn allowedFlds = + mkObjTyInfo (Just desc) (mkTableTy tn) Set.empty (mapFromL _fiName flds) HasuraType where flds = concatMap (either (pure . mkPGColFld) mkRelFld') allowedFlds mkRelFld' (relInfo, allowAgg, _, _, isNullable) = mkRelFld allowAgg relInfo isNullable - txtDescDefault = "columns and relationships of " <>> tn - gqlDesc = G.Description $ case descM of - Nothing -> txtDescDefault - Just (PGDescription txtDesc) -> T.unlines [txtDesc, txtDescDefault] + desc = G.Description $ "columns and relationships of " <>> tn {- type table_aggregate { @@ -367,11 +368,12 @@ table( -} mkSelFld :: QualifiedTable + -> Maybe PGDescription -> ObjFldInfo -mkSelFld tn = +mkSelFld tn descM = mkHsraObjFldInfo (Just desc) fldName args ty where - desc = G.Description $ "fetch data from the table: " <>> tn + desc = mkDescription descM $ "fetch data from the table: " <>> tn fldName = qualObjectToName tn args = fromInpValL $ mkSelArgs tn ty = G.toGT $ G.toNT $ G.toLT $ G.toNT $ mkTableTy tn @@ -385,13 +387,14 @@ table_by_pk( ): table -} mkSelFldPKey - :: QualifiedTable -> [PGColInfo] + :: QualifiedTable + -> [PGColInfo] + -> Maybe PGDescription -> ObjFldInfo -mkSelFldPKey tn cols = +mkSelFldPKey tn cols descM = mkHsraObjFldInfo (Just desc) fldName args ty where - desc = G.Description $ "fetch data from the table: " <> tn - <<> " using primary key columns" + desc = mkDescription descM $ "fetch data from the table: " <> tn <<> " using primary key columns" fldName = mkTableByPkName tn args = fromInpValL $ map colInpVal cols ty = G.toGT $ mkTableTy tn @@ -409,12 +412,12 @@ table_aggregate( -} mkAggSelFld :: QualifiedTable + -> Maybe PGDescription -> ObjFldInfo -mkAggSelFld tn = +mkAggSelFld tn descM = mkHsraObjFldInfo (Just desc) fldName args ty where - desc = G.Description $ "fetch aggregated fields from the table: " - <>> tn + desc = mkDescription descM $ "fetch aggregated fields from the table: " <>> tn fldName = qualObjectToName tn <> "_aggregate" args = fromInpValL $ mkSelArgs tn ty = G.toGT $ G.toNT $ mkTableAggTy tn @@ -807,14 +810,17 @@ mkJSONOpInpVals tn cols = bool jsonbOpArgs [] $ null jsonbCols G.toGT $ mkJSONOpTy tn deleteAtPathOp mkUpdMutFld - :: QualifiedTable -> [PGColInfo] -> ObjFldInfo -mkUpdMutFld tn cols = + :: QualifiedTable + -> [PGColInfo] + -> Maybe PGDescription + -> ObjFldInfo +mkUpdMutFld tn cols descM = mkHsraObjFldInfo (Just desc) fldName (fromInpValL inputValues) $ G.toGT $ mkMutRespTy tn where inputValues = [filterArg, setArg] <> incArg <> mkJSONOpInpVals tn cols - desc = G.Description $ "update data of the table: " <>> tn + desc = mkDescription descM $ "update data of the table: " <>> tn fldName = "update_" <> qualObjectToName tn @@ -838,12 +844,14 @@ delete_table( -} mkDelMutFld - :: QualifiedTable -> ObjFldInfo -mkDelMutFld tn = + :: QualifiedTable + -> Maybe PGDescription + -> ObjFldInfo +mkDelMutFld tn descM = mkHsraObjFldInfo (Just desc) fldName (fromInpValL [filterArg]) $ G.toGT $ mkMutRespTy tn where - desc = G.Description $ "delete data from the table: " <>> tn + desc = mkDescription descM $ "delete data from the table: " <>> tn fldName = "delete_" <> qualObjectToName tn @@ -995,14 +1003,16 @@ insert_table( -} mkInsMutFld - :: QualifiedTable -> Bool -> ObjFldInfo -mkInsMutFld tn isUpsertable = + :: QualifiedTable + -> Bool + -> Maybe PGDescription + -> ObjFldInfo +mkInsMutFld tn isUpsertable descM = mkHsraObjFldInfo (Just desc) fldName (fromInpValL inputVals) $ G.toGT $ mkMutRespTy tn where inputVals = catMaybes [Just objectsArg , onConflictInpVal] - desc = G.Description $ - "insert data into the table: " <>> tn + desc = mkDescription descM $ "insert data into the table: " <>> tn fldName = "insert_" <> qualObjectToName tn @@ -1232,8 +1242,6 @@ mkOnConflictTypes tn uniqueOrPrimaryCons cols = mkGCtxRole' :: QualifiedTable - -- table description - -> Maybe PGDescription -- insert permission -> Maybe ([PGColInfo], RelationInfoMap) -- select permission @@ -1250,7 +1258,7 @@ mkGCtxRole' -- all functions -> [FunctionInfo] -> TyAgg -mkGCtxRole' tn descM insPermM selPermM updColsM +mkGCtxRole' tn insPermM selPermM updColsM delPermM pkeyCols constraints viM funcs = TyAgg (mkTyInfoMap allTypes) fieldMap scalars ordByCtx @@ -1362,7 +1370,7 @@ mkGCtxRole' tn descM insPermM selPermM updColsM && any (`isMutable` viM) [viIsInsertable, viIsUpdatable, viIsDeletable] -- table obj - selObjM = mkTableObj tn descM <$> selFldsM + selObjM = mkTableObj tn <$> selFldsM -- aggregate objs and order by inputs (aggObjs, aggOrdByInps) = case selPermM of @@ -1404,6 +1412,7 @@ mkGCtxRole' tn descM insPermM selPermM updColsM getRootFldsRole' :: QualifiedTable + -> Maybe PGDescription -> [PGCol] -> [ConstraintName] -> FieldInfoMap @@ -1414,7 +1423,7 @@ getRootFldsRole' -> Maybe (AnnBoolExpPartialSQL, [T.Text]) -- delete filter -> Maybe ViewInfo -> RootFlds -getRootFldsRole' tn primCols constraints fields funcs insM selM updM delM viM = +getRootFldsRole' tn descM primCols constraints fields funcs insM selM updM delM viM = RootFlds mFlds where allCols = getCols fields @@ -1440,17 +1449,17 @@ getRootFldsRole' tn primCols constraints fields funcs insM selM updM delM viM = getInsDet (hdrs, upsertPerm) = let isUpsertable = upsertable constraints upsertPerm $ isJust viM in ( OCInsert $ InsOpCtx tn $ hdrs `union` maybe [] (\(_, _, _, x) -> x) updM - , Right $ mkInsMutFld tn isUpsertable + , Right $ mkInsMutFld tn isUpsertable descM ) getUpdDet (updCols, preSetCols, updFltr, hdrs) = ( OCUpdate $ UpdOpCtx tn hdrs updFltr preSetCols allCols - , Right $ mkUpdMutFld tn $ getColInfos updCols colInfos + , Right $ mkUpdMutFld tn (getColInfos updCols colInfos) descM ) getDelDet (delFltr, hdrs) = ( OCDelete $ DelOpCtx tn hdrs delFltr allCols - , Right $ mkDelMutFld tn + , Right $ mkDelMutFld tn descM ) getSelDet (selFltr, pLimit, hdrs, _) = selFldHelper OCSelect mkSelFld selFltr pLimit hdrs @@ -1461,7 +1470,7 @@ getRootFldsRole' tn primCols constraints fields funcs insM selM updM delM viM = selFldHelper f g pFltr pLimit hdrs = ( f $ SelOpCtx tn hdrs pFltr pLimit - , Left $ g tn + , Left $ g tn descM ) getPKeySelDet Nothing _ = Nothing @@ -1469,7 +1478,7 @@ getRootFldsRole' tn primCols constraints fields funcs insM selM updM delM viM = getPKeySelDet (Just (selFltr, _, hdrs, _)) pCols = Just ( OCSelectPkey $ SelPkOpCtx tn hdrs selFltr $ mapFromL (mkColName . pgiName) pCols - , Left $ mkSelFldPKey tn pCols + , Left $ mkSelFldPKey tn pCols descM ) getFuncQueryFlds (selFltr, pLimit, hdrs, _) = @@ -1599,9 +1608,9 @@ mkGCtxRole tableCache tn descM fields pCols constraints funcs viM role permInfo let insPermM = snd <$> tabInsInfoM insCtxM = fst <$> tabInsInfoM updColsM = filterColInfos . upiCols <$> _permUpd permInfo - tyAgg = mkGCtxRole' tn descM insPermM selPermM updColsM + tyAgg = mkGCtxRole' tn insPermM selPermM updColsM (void $ _permDel permInfo) pColInfos constraints viM funcs - rootFlds = getRootFldsRole tn pCols constraints fields funcs viM permInfo + rootFlds = getRootFldsRole tn descM pCols constraints fields funcs viM permInfo insCtxMap = maybe Map.empty (Map.singleton tn) insCtxM return (tyAgg, rootFlds, insCtxMap) where @@ -1613,6 +1622,7 @@ mkGCtxRole tableCache tn descM fields pCols constraints funcs viM role permInfo getRootFldsRole :: QualifiedTable + -> Maybe PGDescription -> [PGCol] -> [ConstraintName] -> FieldInfoMap @@ -1620,8 +1630,8 @@ getRootFldsRole -> Maybe ViewInfo -> RolePermInfo -> RootFlds -getRootFldsRole tn pCols constraints fields funcs viM (RolePermInfo insM selM updM delM) = - getRootFldsRole' tn pCols constraints fields funcs +getRootFldsRole tn descM pCols constraints fields funcs viM (RolePermInfo insM selM updM delM) = + getRootFldsRole' tn descM pCols constraints fields funcs (mkIns <$> insM) (mkSel <$> selM) (mkUpd <$> updM) (mkDel <$> delM) viM @@ -1647,7 +1657,7 @@ mkGCtxMapTable tableCache funcCache tabInfo = do m <- Map.traverseWithKey (mkGCtxRole tableCache tn descM fields pkeyCols validConstraints tabFuncs viewInfo) rolePerms adminInsCtx <- mkAdminInsCtx tn tableCache fields - let adminCtx = mkGCtxRole' tn descM (Just (colInfos, icRelations adminInsCtx)) + let adminCtx = mkGCtxRole' tn (Just (colInfos, icRelations adminInsCtx)) (Just (True, selFlds)) (Just colInfos) (Just ()) pkeyColInfos validConstraints viewInfo tabFuncs adminInsCtxMap = Map.singleton tn adminInsCtx @@ -1664,7 +1674,7 @@ mkGCtxMapTable tableCache funcCache tabInfo = do FIColumn pgColInfo -> Left pgColInfo FIRelationship relInfo -> Right (relInfo, True, noFilter, Nothing, isRelNullable fields relInfo) adminRootFlds = - getRootFldsRole' tn pkeyCols validConstraints fields tabFuncs + getRootFldsRole' tn descM pkeyCols validConstraints fields tabFuncs (Just ([], True)) (Just (noFilter, Nothing, [], True)) (Just (validColNames, mempty, noFilter, [])) (Just (noFilter, [])) viewInfo diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs index 66184670d092b..b0370d20ffb68 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs @@ -41,6 +41,7 @@ data RawFuncInfo , rfiInputArgTypes :: ![PGColType] , rfiInputArgNames :: ![T.Text] , rfiReturnsTable :: !Bool + , rfiDescription :: !(Maybe PGDescription) } deriving (Show, Eq) $(deriveJSON (aesonDrop 3 snakeCase) ''RawFuncInfo) @@ -83,10 +84,10 @@ mkFunctionInfo qf rawFuncInfo = do let funcArgsSeq = Seq.fromList funcArgs dep = SchemaDependency (SOTable retTable) "table" retTable = QualifiedObject retSn (TableName retN) - return $ FunctionInfo qf False funTy funcArgsSeq retTable [dep] + return $ FunctionInfo qf False funTy funcArgsSeq retTable [dep] descM where - RawFuncInfo hasVariadic funTy retSn retN retTyTyp - retSet inpArgTyps inpArgNames returnsTab + RawFuncInfo hasVariadic funTy retSn retN retTyTyp retSet + inpArgTyps inpArgNames returnsTab descM = rawFuncInfo saveFunctionToCatalog :: QualifiedFunction -> Bool -> Q.TxE QErr () diff --git a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs index c948400c760c6..22ac4e9b1af13 100644 --- a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs +++ b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs @@ -405,6 +405,7 @@ data FunctionInfo , fiInputArgs :: !(Seq.Seq FunctionArg) , fiReturnType :: !QualifiedTable , fiDeps :: ![SchemaDependency] + , fiDescription :: !(Maybe PGDescription) } deriving (Show, Eq) $(deriveToJSON (aesonDrop 2 snakeCase) ''FunctionInfo) From c26324b7e662f2614ed4007b0a316c58641f554a Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Fri, 12 Jul 2019 15:15:41 +0530 Subject: [PATCH 05/12] add Postgres comments to function description --- server/src-lib/Hasura/GraphQL/Schema.hs | 21 ++-- server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs | 21 ++-- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 2 +- server/src-rsr/initialise.sql | 3 + server/src-rsr/migrate_from_17_to_18.sql | 115 ++++++++++++++++++ 5 files changed, 144 insertions(+), 18 deletions(-) diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 6e725d7124231..1f533dfefbd23 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -447,15 +447,17 @@ mkFuncArgs funInfo = funcInpArgs = bool [funcInpArg] [] $ null funcArgs mkFuncQueryFld - :: FunctionInfo -> ObjFldInfo -mkFuncQueryFld funInfo = + :: FunctionInfo + -> Maybe PGDescription + -> ObjFldInfo +mkFuncQueryFld funInfo descM = mkHsraObjFldInfo (Just desc) fldName (mkFuncArgs funInfo) ty where retTable = fiReturnType funInfo funcName = fiName funInfo - desc = G.Description $ "execute function " <> funcName - <<> " which returns " <>> retTable + desc = mkDescription descM $ + "execute function " <> funcName <<> " which returns " <>> retTable fldName = qualObjectToName funcName ty = G.toGT $ G.toNT $ G.toLT $ G.toNT $ mkTableTy retTable @@ -472,14 +474,17 @@ function_aggregate( -} mkFuncAggQueryFld - :: FunctionInfo -> ObjFldInfo -mkFuncAggQueryFld funInfo = + :: FunctionInfo + -> Maybe PGDescription + -> ObjFldInfo +mkFuncAggQueryFld funInfo descM = mkHsraObjFldInfo (Just desc) fldName (mkFuncArgs funInfo) ty where funcName = fiName funInfo retTable = fiReturnType funInfo - desc = G.Description $ "execute function " <> funcName + desc = mkDescription descM $ + "execute function " <> funcName <<> " and query aggregates on result of table type " <>> retTable @@ -1491,7 +1496,7 @@ getRootFldsRole' tn descM primCols constraints fields funcs insM selM updM delM funcFldHelper f g pFltr pLimit hdrs = flip map funcs $ \fi -> ( f $ FuncQOpCtx tn hdrs pFltr pLimit (fiName fi) $ mkFuncArgItemSeq fi - , Left $ g fi + , Left $ g fi $ fiDescription fi ) mkFuncArgItemSeq fi = Seq.fromList $ diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs index e6869a0415e34..d7fb430545d3b 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs @@ -196,10 +196,11 @@ getSchemaChangeDeps schemaDiff = do data FunctionMeta = FunctionMeta - { fmOid :: !Int - , fmSchema :: !SchemaName - , fmName :: !FunctionName - , fmType :: !FunctionType + { fmOid :: !Int + , fmSchema :: !SchemaName + , fmName :: !FunctionName + , fmType :: !FunctionType + , fmDescription :: !(Maybe PGDescription) } deriving (Show, Eq) $(deriveJSON (aesonDrop 2 snakeCase) ''FunctionMeta) @@ -214,7 +215,8 @@ fetchFunctionMeta = 'oid', p.oid :: integer, 'schema', f.function_schema, 'name', f.function_name, - 'type', f.function_type + 'type', f.function_type, + 'description', f.description ) AS function_meta FROM hdb_catalog.hdb_function_agg f @@ -225,13 +227,13 @@ fetchFunctionMeta = ) WHERE f.function_schema <> 'hdb_catalog' - GROUP BY p.oid, f.function_schema, f.function_name, f.function_type + GROUP BY p.oid, f.function_schema, f.function_name, f.function_type, f.description |] () False data FunctionDiff = FunctionDiff { fdDropped :: ![QualifiedFunction] - , fdAltered :: ![(QualifiedFunction, FunctionType)] + , fdAltered :: ![(QualifiedFunction, FunctionType, Maybe PGDescription)] } deriving (Show, Eq) getFuncDiff :: [FunctionMeta] -> [FunctionMeta] -> FunctionDiff @@ -242,8 +244,9 @@ getFuncDiff oldMeta newMeta = alteredFuncs = mapMaybe mkAltered $ getOverlap fmOid oldMeta newMeta mkAltered (oldfm, newfm) = let isTypeAltered = fmType oldfm /= fmType newfm - alteredFunc = (funcFromMeta oldfm, fmType newfm) - in bool Nothing (Just alteredFunc) isTypeAltered + isDescriptionAltered = fmDescription oldfm /= fmDescription newfm + alteredFunc = (funcFromMeta oldfm, fmType newfm, fmDescription newfm) + in bool Nothing (Just alteredFunc) $ isTypeAltered || isDescriptionAltered getOverloadedFuncs :: [QualifiedFunction] -> [FunctionMeta] -> [QualifiedFunction] diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index f5c0415597930..34726d0fbe622 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -572,7 +572,7 @@ execWithMDCheck (RunSQL t cascade _) = do delFunctionFromCache qf -- Process altered functions - forM_ alteredFuncs $ \(qf, newTy) -> + forM_ alteredFuncs $ \(qf, newTy, _) -> when (newTy == FTVOLATILE) $ throw400 NotSupported $ "type of function " <> qf <<> " is altered to \"VOLATILE\" which is not supported now" diff --git a/server/src-rsr/initialise.sql b/server/src-rsr/initialise.sql index 99b5ebb8fe39d..80413da474f9b 100644 --- a/server/src-rsr/initialise.sql +++ b/server/src-rsr/initialise.sql @@ -333,6 +333,7 @@ CREATE VIEW hdb_catalog.hdb_function_agg AS SELECT p.proname::text AS function_name, pn.nspname::text AS function_schema, + pd.description, CASE WHEN (p.provariadic = (0) :: oid) THEN false @@ -388,6 +389,7 @@ FROM JOIN pg_namespace pn ON (pn.oid = p.pronamespace) JOIN pg_type rt ON (rt.oid = p.prorettype) JOIN pg_namespace rtn ON (rtn.oid = rt.typnamespace) + LEFT JOIN pg_description pd ON p.oid = pd.objoid WHERE pn.nspname :: text NOT LIKE 'pg_%' AND pn.nspname :: text NOT IN ('information_schema', 'hdb_catalog', 'hdb_views') @@ -536,6 +538,7 @@ CREATE VIEW hdb_catalog.hdb_function_info_agg AS ( FROM ( SELECT + description, has_variadic, function_type, return_type_schema, diff --git a/server/src-rsr/migrate_from_17_to_18.sql b/server/src-rsr/migrate_from_17_to_18.sql index 413a9ce8e6011..8dc2c758e05b2 100644 --- a/server/src-rsr/migrate_from_17_to_18.sql +++ b/server/src-rsr/migrate_from_17_to_18.sql @@ -88,3 +88,118 @@ from AND tables.table_name = descriptions.table_name ) ); + +DROP VIEW hdb_catalog.hdb_function_info_agg; +DROP VIEW hdb_catalog.hdb_function_agg; + +CREATE VIEW hdb_catalog.hdb_function_agg AS +( +SELECT + p.proname::text AS function_name, + pn.nspname::text AS function_schema, + pd.description, + + CASE + WHEN (p.provariadic = (0) :: oid) THEN false + ELSE true + END AS has_variadic, + + CASE + WHEN ( + (p.provolatile) :: text = ('i' :: character(1)) :: text + ) THEN 'IMMUTABLE' :: text + WHEN ( + (p.provolatile) :: text = ('s' :: character(1)) :: text + ) THEN 'STABLE' :: text + WHEN ( + (p.provolatile) :: text = ('v' :: character(1)) :: text + ) THEN 'VOLATILE' :: text + ELSE NULL :: text + END AS function_type, + + pg_get_functiondef(p.oid) AS function_definition, + + rtn.nspname::text AS return_type_schema, + rt.typname::text AS return_type_name, + + CASE + WHEN ((rt.typtype) :: text = ('b' :: character(1)) :: text) THEN 'BASE' :: text + WHEN ((rt.typtype) :: text = ('c' :: character(1)) :: text) THEN 'COMPOSITE' :: text + WHEN ((rt.typtype) :: text = ('d' :: character(1)) :: text) THEN 'DOMAIN' :: text + WHEN ((rt.typtype) :: text = ('e' :: character(1)) :: text) THEN 'ENUM' :: text + WHEN ((rt.typtype) :: text = ('r' :: character(1)) :: text) THEN 'RANGE' :: text + WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSUEDO' :: text + ELSE NULL :: text + END AS return_type_type, + p.proretset AS returns_set, + ( SELECT + COALESCE(json_agg(q.type_name), '[]') + FROM + ( + SELECT + pt.typname AS type_name, + pat.ordinality + FROM + unnest( + COALESCE(p.proallargtypes, (p.proargtypes) :: oid []) + ) WITH ORDINALITY pat(oid, ordinality) + LEFT JOIN pg_type pt ON ((pt.oid = pat.oid)) + ORDER BY pat.ordinality ASC + ) q + ) AS input_arg_types, + to_json(COALESCE(p.proargnames, ARRAY [] :: text [])) AS input_arg_names +FROM + pg_proc p + JOIN pg_namespace pn ON (pn.oid = p.pronamespace) + JOIN pg_type rt ON (rt.oid = p.prorettype) + JOIN pg_namespace rtn ON (rtn.oid = rt.typnamespace) + LEFT JOIN pg_description pd ON p.oid = pd.objoid +WHERE + pn.nspname :: text NOT LIKE 'pg_%' + AND pn.nspname :: text NOT IN ('information_schema', 'hdb_catalog', 'hdb_views') + AND (NOT EXISTS ( + SELECT + 1 + FROM + pg_aggregate + WHERE + ((pg_aggregate.aggfnoid) :: oid = p.oid) + ) + ) +); + +CREATE VIEW hdb_catalog.hdb_function_info_agg AS ( + SELECT + function_name, + function_schema, + row_to_json ( + ( + SELECT + e + FROM + ( + SELECT + description, + has_variadic, + function_type, + return_type_schema, + return_type_name, + return_type_type, + returns_set, + input_arg_types, + input_arg_names, + exists( + SELECT + 1 + FROM + information_schema.tables + WHERE + table_schema = return_type_schema + AND table_name = return_type_name + ) AS returns_table + ) AS e + ) + ) AS "function_info" + FROM + hdb_catalog.hdb_function_agg +); From aef5d0f93d03fdc3657b3422675a55abce84ea6e Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Thu, 1 Aug 2019 12:25:49 +0530 Subject: [PATCH 06/12] fix hdb_table_info_agg view --- server/src-rsr/initialise.sql | 1 + server/src-rsr/migrate_from_19_to_20.sql | 1 + 2 files changed, 2 insertions(+) diff --git a/server/src-rsr/initialise.sql b/server/src-rsr/initialise.sql index a4e42d96744a8..a7e7e0bd0298c 100644 --- a/server/src-rsr/initialise.sql +++ b/server/src-rsr/initialise.sql @@ -516,6 +516,7 @@ from from pg_class pc left join pg_namespace pn on pn.oid = pc.relnamespace left join pg_description pd on pd.objoid = pc.oid + where pd.objsubid = 0 ) descriptions on ( tables.table_schema = descriptions.table_schema AND tables.table_name = descriptions.table_name diff --git a/server/src-rsr/migrate_from_19_to_20.sql b/server/src-rsr/migrate_from_19_to_20.sql index 8dc2c758e05b2..cc1a726a7cc1e 100644 --- a/server/src-rsr/migrate_from_19_to_20.sql +++ b/server/src-rsr/migrate_from_19_to_20.sql @@ -83,6 +83,7 @@ from from pg_class pc left join pg_namespace pn on pn.oid = pc.relnamespace left join pg_description pd on pd.objoid = pc.oid + where pd.objsubid = 0 ) descriptions on ( tables.table_schema = descriptions.table_schema AND tables.table_name = descriptions.table_name From 78ddc3cc38553b225b8ea435d0982650bdce4ac0 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Thu, 1 Aug 2019 13:12:52 +0530 Subject: [PATCH 07/12] support column comments --- server/src-lib/Hasura/GraphQL/Schema.hs | 13 +++++++------ server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs | 5 +++-- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 9 +++++---- server/src-lib/Hasura/RQL/DML/Internal.hs | 3 ++- server/src-lib/Hasura/RQL/DML/Returning.hs | 4 ++-- server/src-lib/Hasura/RQL/GBoolExp.hs | 7 ++++--- server/src-lib/Hasura/RQL/Types/Common.hs | 7 ++++--- server/src-rsr/initialise.sql | 8 +++++++- server/src-rsr/migrate_from_19_to_20.sql | 8 +++++++- server/src-rsr/table_meta.sql | 7 ++++++- 10 files changed, 47 insertions(+), 24 deletions(-) diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 4b1b7b5ae7784..43529f75016c8 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -67,7 +67,7 @@ isValidRel rn rt = isValidName (mkRelName rn) && isValidObjectName rt isValidField :: FieldInfo -> Bool isValidField = \case - FIColumn (PGColInfo col _ _) -> isValidCol col + FIColumn colInfo -> isValidCol $ pgiName colInfo FIRelationship (RelInfo rn _ _ remTab _) -> isValidRel rn remTab upsertable :: [ConstraintName] -> Bool -> Bool -> Bool @@ -171,9 +171,10 @@ mkPGColParams = \case ] mkPGColFld :: PGColInfo -> ObjFldInfo -mkPGColFld (PGColInfo colName colTy isNullable) = - mkHsraObjFldInfo Nothing n (mkPGColParams colTy) ty +mkPGColFld (PGColInfo colName colTy isNullable pgDesc) = + mkHsraObjFldInfo desc n (mkPGColParams colTy) ty where + desc = (G.Description . getPGDescription) <$> pgDesc n = G.Name $ getPGColTxt colName ty = bool notNullTy nullTy isNullable scalarTy = mkScalarTy colTy @@ -383,7 +384,7 @@ mkSelFldPKey tn cols descM = fldName = mkTableByPkName tn args = fromInpValL $ map colInpVal cols ty = G.toGT $ mkTableTy tn - colInpVal (PGColInfo n typ _) = + colInpVal (PGColInfo n typ _ _) = InpValInfo Nothing (mkColName n) Nothing $ G.toGT $ G.toNT $ mkScalarTy typ {- @@ -541,13 +542,13 @@ mkBoolExpInp tn fields = ] mkFldExpInp = \case - Left (PGColInfo colName colTy _) -> + Left (PGColInfo colName colTy _ _) -> mk (mkColName colName) (mkCompExpTy colTy) Right (RelInfo relName _ _ remTab _, _, _, _, _) -> mk (mkRelName relName) (mkBoolExpTy remTab) mkPGColInp :: PGColInfo -> InpValInfo -mkPGColInp (PGColInfo colName colTy _) = +mkPGColInp (PGColInfo colName colTy _ _) = InpValInfo Nothing (G.Name $ getPGColTxt colName) Nothing $ G.toGT $ mkScalarTy colTy diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs index d7fb430545d3b..8f66611248353 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Diff.hs @@ -42,6 +42,7 @@ data PGColMeta , pcmOrdinalPosition :: !Int , pcmDataType :: !PGColType , pcmIsNullable :: !Bool + , pcmDescription :: !(Maybe PGDescription) } deriving (Show, Eq) $(deriveJSON (aesonDrop 3 snakeCase){omitNothingFields=True} ''PGColMeta) @@ -120,8 +121,8 @@ getTableDiff oldtm newtm = existingCols = getOverlap pcmOrdinalPosition oldCols newCols - pcmToPci (PGColMeta colName _ colType isNullable) - = PGColInfo colName colType isNullable + pcmToPci (PGColMeta colName _ colType isNullable descM) + = PGColInfo colName colType isNullable descM alteredCols = flip map (filter (uncurry (/=)) existingCols) $ pcmToPci *** pcmToPci diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index 2963e53b833e6..271c4d938aa11 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -179,7 +179,8 @@ processTableChanges ti tableDiff = do procAddedCols tn = -- In the newly added columns check that there is no conflict with relationships - forM_ addedCols $ \pci@(PGColInfo colName _ _) -> + forM_ addedCols $ \pci -> do + let colName = pgiName pci case M.lookup (fromPGCol colName) $ tiFieldInfoMap ti of Just (FIRelationship _) -> throw400 AlreadyExists $ "cannot add column " <> colName @@ -188,8 +189,8 @@ processTableChanges ti tableDiff = do _ -> addColToCache colName pci tn procAlteredCols sc tn = fmap or $ forM alteredCols $ - \( PGColInfo oColName oColTy oNullable - , npci@(PGColInfo nColName nColTy nNullable) + \( PGColInfo oColName oColTy oNullable oDesc + , npci@(PGColInfo nColName nColTy nNullable nDesc) ) -> if | oColName /= nColName -> do renameColInCatalog oColName nColName tn ti @@ -203,7 +204,7 @@ processTableChanges ti tableDiff = do reportSchemaObjs depObjs updColInCache nColName npci tn return False - | oNullable /= nNullable -> do + | oNullable /= nNullable || oDesc /= nDesc -> do updColInCache nColName npci tn return False | otherwise -> return False diff --git a/server/src-lib/Hasura/RQL/DML/Internal.hs b/server/src-lib/Hasura/RQL/DML/Internal.hs index 3e0f475cb84bc..1f214c7d5824b 100644 --- a/server/src-lib/Hasura/RQL/DML/Internal.hs +++ b/server/src-lib/Hasura/RQL/DML/Internal.hs @@ -188,7 +188,8 @@ checkOnColExp -> AnnBoolExpFldSQL -> m AnnBoolExpFldSQL checkOnColExp spi sessVarBldr annFld = case annFld of - AVCol (PGColInfo cn _ _) _ -> do + AVCol colInfo _ -> do + let cn = pgiName colInfo checkSelOnCol spi cn return annFld AVRel relInfo nesAnn -> do diff --git a/server/src-lib/Hasura/RQL/DML/Returning.hs b/server/src-lib/Hasura/RQL/DML/Returning.hs index f81de53d5bbf4..2f31354bb7366 100644 --- a/server/src-lib/Hasura/RQL/DML/Returning.hs +++ b/server/src-lib/Hasura/RQL/DML/Returning.hs @@ -56,8 +56,8 @@ pgColsFromMutFld = \case MExp _ -> [] MRet selFlds -> flip mapMaybe selFlds $ \(_, annFld) -> case annFld of - FCol (PGColInfo col colTy _) _ -> Just (col, colTy) - _ -> Nothing + FCol (PGColInfo col colTy _ _) _ -> Just (col, colTy) + _ -> Nothing pgColsFromMutFlds :: MutFlds -> [(PGCol, PGColType)] pgColsFromMutFlds = concatMap (pgColsFromMutFld . snd) diff --git a/server/src-lib/Hasura/RQL/GBoolExp.hs b/server/src-lib/Hasura/RQL/GBoolExp.hs index 59f082d6160bf..fe7216a03c316 100644 --- a/server/src-lib/Hasura/RQL/GBoolExp.hs +++ b/server/src-lib/Hasura/RQL/GBoolExp.hs @@ -312,7 +312,7 @@ annColExp annColExp rhsParser colInfoMap (ColExp fieldName colVal) = do colInfo <- askFieldInfo colInfoMap fieldName case colInfo of - FIColumn (PGColInfo _ PGJSON _) -> + FIColumn (PGColInfo _ PGJSON _ _) -> throwError (err400 UnexpectedPayload "JSON column can not be part of where clause") FIColumn pgi -> AVCol pgi <$> parseOperationsExpression rhsParser colInfoMap pgi colVal @@ -335,8 +335,9 @@ convBoolRhs' tq = convColRhs :: S.Qual -> AnnBoolExpFldSQL -> State Word64 S.BoolExp convColRhs tableQual = \case - AVCol (PGColInfo cn _ _) opExps -> do - let bExps = map (mkColCompExp tableQual cn) opExps + AVCol colInfo opExps -> do + let cn = pgiName colInfo + bExps = map (mkColCompExp tableQual cn) opExps return $ foldr (S.BEBin S.AndOp) (S.BELit True) bExps AVRel (RelInfo _ _ colMapping relTN _) nesAnn -> do diff --git a/server/src-lib/Hasura/RQL/Types/Common.hs b/server/src-lib/Hasura/RQL/Types/Common.hs index 908262b708b87..080030b56cb2c 100644 --- a/server/src-lib/Hasura/RQL/Types/Common.hs +++ b/server/src-lib/Hasura/RQL/Types/Common.hs @@ -40,9 +40,10 @@ import qualified PostgreSQL.Binary.Decoding as PD data PGColInfo = PGColInfo - { pgiName :: !PGCol - , pgiType :: !PGColType - , pgiIsNullable :: !Bool + { pgiName :: !PGCol + , pgiType :: !PGColType + , pgiIsNullable :: !Bool + , pgiDescription :: !(Maybe PGDescription) } deriving (Show, Eq) $(deriveJSON (aesonDrop 3 snakeCase) ''PGColInfo) diff --git a/server/src-rsr/initialise.sql b/server/src-rsr/initialise.sql index a7e7e0bd0298c..a60d405878f4e 100644 --- a/server/src-rsr/initialise.sql +++ b/server/src-rsr/initialise.sql @@ -455,11 +455,17 @@ from 'type', udt_name, 'is_nullable', - is_nullable :: boolean + is_nullable :: boolean, + 'description', + col_description(pc.oid, c.ordinal_position) ) ) as columns from information_schema.columns c + left join pg_class pc on pc.relname = c.table_name + left join pg_namespace pn on ( pn.oid = pc.relnamespace + and pn.nspname = c.table_schema + ) group by c.table_schema, c.table_name diff --git a/server/src-rsr/migrate_from_19_to_20.sql b/server/src-rsr/migrate_from_19_to_20.sql index cc1a726a7cc1e..437a2b1eb30b8 100644 --- a/server/src-rsr/migrate_from_19_to_20.sql +++ b/server/src-rsr/migrate_from_19_to_20.sql @@ -22,11 +22,17 @@ from 'type', udt_name, 'is_nullable', - is_nullable :: boolean + is_nullable :: boolean, + 'description', + col_description(pc.oid, c.ordinal_position) ) ) as columns from information_schema.columns c + left join pg_class pc on pc.relname = c.table_name + left join pg_namespace pn on ( pn.oid = pc.relnamespace + and pn.nspname = c.table_schema + ) group by c.table_schema, c.table_name diff --git a/server/src-rsr/table_meta.sql b/server/src-rsr/table_meta.sql index 7d85313da2532..9970cab254319 100644 --- a/server/src-rsr/table_meta.sql +++ b/server/src-rsr/table_meta.sql @@ -32,12 +32,17 @@ FROM column_name, udt_name AS data_type, ordinal_position, - is_nullable :: boolean + is_nullable :: boolean, + col_description(pc.oid, ordinal_position) AS description ) r ) ) as columns FROM information_schema.columns + left join pg_class pc on pc.relname = table_name + left join pg_namespace pn on ( pn.oid = pc.relnamespace + and pn.nspname = table_schema + ) GROUP BY table_schema, table_name From 7c54604ac885b5a88a1ae99935223609617a56ee Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Thu, 1 Aug 2019 15:17:44 +0530 Subject: [PATCH 08/12] add table description to table type and remove from resolvers --- server/src-lib/Hasura/GraphQL/Schema.hs | 92 ++++++++++--------------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/server/src-lib/Hasura/GraphQL/Schema.hs b/server/src-lib/Hasura/GraphQL/Schema.hs index 43529f75016c8..2dd8e00259e84 100644 --- a/server/src-lib/Hasura/GraphQL/Schema.hs +++ b/server/src-lib/Hasura/GraphQL/Schema.hs @@ -112,7 +112,7 @@ isAggFld = flip elem (numAggOps <> compAggOps) mkDescription :: Maybe PGDescription -> Text -> G.Description mkDescription descM defaultTxt = G.Description $ case descM of Nothing -> defaultTxt - Just (PGDescription descTxt) -> T.unlines [descTxt, defaultTxt] + Just (PGDescription descTxt) -> T.unlines [descTxt, "\n", defaultTxt] mkColName :: PGCol -> G.Name mkColName (PGCol n) = G.Name n @@ -253,15 +253,16 @@ type table { -} mkTableObj :: QualifiedTable + -> Maybe PGDescription -> [SelField] -> ObjTyInfo -mkTableObj tn allowedFlds = +mkTableObj tn descM allowedFlds = mkObjTyInfo (Just desc) (mkTableTy tn) Set.empty (mapFromL _fiName flds) TLHasuraType where flds = concatMap (either (pure . mkPGColFld) mkRelFld') allowedFlds mkRelFld' (relInfo, allowAgg, _, _, isNullable) = mkRelFld allowAgg relInfo isNullable - desc = G.Description $ "columns and relationships of " <>> tn + desc = mkDescription descM $ "columns and relationships of " <>> tn {- type table_aggregate { @@ -352,14 +353,11 @@ table( ): [table!]! -} -mkSelFld - :: QualifiedTable - -> Maybe PGDescription - -> ObjFldInfo -mkSelFld tn descM = +mkSelFld :: QualifiedTable -> ObjFldInfo +mkSelFld tn = mkHsraObjFldInfo (Just desc) fldName args ty where - desc = mkDescription descM $ "fetch data from the table: " <>> tn + desc = G.Description $ "fetch data from the table: " <>> tn fldName = qualObjectToName tn args = fromInpValL $ mkSelArgs tn ty = G.toGT $ G.toNT $ G.toLT $ G.toNT $ mkTableTy tn @@ -372,15 +370,12 @@ table_by_pk( coln: valuen! ): table -} -mkSelFldPKey - :: QualifiedTable - -> [PGColInfo] - -> Maybe PGDescription - -> ObjFldInfo -mkSelFldPKey tn cols descM = +mkSelFldPKey :: QualifiedTable -> [PGColInfo] -> ObjFldInfo +mkSelFldPKey tn cols = mkHsraObjFldInfo (Just desc) fldName args ty where - desc = mkDescription descM $ "fetch data from the table: " <> tn <<> " using primary key columns" + desc = G.Description $ "fetch data from the table: " + <> tn <<> " using primary key columns" fldName = mkTableByPkName tn args = fromInpValL $ map colInpVal cols ty = G.toGT $ mkTableTy tn @@ -396,14 +391,11 @@ table_aggregate( ): table_aggregate! -} -mkAggSelFld - :: QualifiedTable - -> Maybe PGDescription - -> ObjFldInfo -mkAggSelFld tn descM = +mkAggSelFld :: QualifiedTable -> ObjFldInfo +mkAggSelFld tn = mkHsraObjFldInfo (Just desc) fldName args ty where - desc = mkDescription descM $ "fetch aggregated fields from the table: " <>> tn + desc = G.Description $ "fetch aggregated fields from the table: " <>> tn fldName = qualObjectToName tn <> "_aggregate" args = fromInpValL $ mkSelArgs tn ty = G.toGT $ G.toNT $ mkTableAggTy tn @@ -803,15 +795,14 @@ mkJSONOpInpVals tn cols = bool jsonbOpArgs [] $ null jsonbCols mkUpdMutFld :: QualifiedTable -> [PGColInfo] - -> Maybe PGDescription -> ObjFldInfo -mkUpdMutFld tn cols descM = +mkUpdMutFld tn cols = mkHsraObjFldInfo (Just desc) fldName (fromInpValL inputValues) $ G.toGT $ mkMutRespTy tn where inputValues = [filterArg, setArg] <> incArg <> mkJSONOpInpVals tn cols - desc = mkDescription descM $ "update data of the table: " <>> tn + desc = G.Description $ "update data of the table: " <>> tn fldName = "update_" <> qualObjectToName tn @@ -834,15 +825,12 @@ delete_table( -} -mkDelMutFld - :: QualifiedTable - -> Maybe PGDescription - -> ObjFldInfo -mkDelMutFld tn descM = +mkDelMutFld :: QualifiedTable -> ObjFldInfo +mkDelMutFld tn = mkHsraObjFldInfo (Just desc) fldName (fromInpValL [filterArg]) $ G.toGT $ mkMutRespTy tn where - desc = mkDescription descM $ "delete data from the table: " <>> tn + desc = G.Description $ "delete data from the table: " <>> tn fldName = "delete_" <> qualObjectToName tn @@ -993,17 +981,13 @@ insert_table( ): table_mutation_response! -} -mkInsMutFld - :: QualifiedTable - -> Bool - -> Maybe PGDescription - -> ObjFldInfo -mkInsMutFld tn isUpsertable descM = +mkInsMutFld :: QualifiedTable -> Bool -> ObjFldInfo +mkInsMutFld tn isUpsertable = mkHsraObjFldInfo (Just desc) fldName (fromInpValL inputVals) $ G.toGT $ mkMutRespTy tn where inputVals = catMaybes [Just objectsArg , onConflictInpVal] - desc = mkDescription descM $ "insert data into the table: " <>> tn + desc = G.Description $ "insert data into the table: " <>> tn fldName = "insert_" <> qualObjectToName tn @@ -1233,6 +1217,8 @@ mkOnConflictTypes tn uniqueOrPrimaryCons cols = mkGCtxRole' :: QualifiedTable + -- Postgres description + -> Maybe PGDescription -- insert permission -> Maybe ([PGColInfo], RelationInfoMap) -- select permission @@ -1249,7 +1235,7 @@ mkGCtxRole' -- all functions -> [FunctionInfo] -> TyAgg -mkGCtxRole' tn insPermM selPermM updColsM +mkGCtxRole' tn descM insPermM selPermM updColsM delPermM pkeyCols constraints viM funcs = TyAgg (mkTyInfoMap allTypes) fieldMap scalars ordByCtx @@ -1361,7 +1347,7 @@ mkGCtxRole' tn insPermM selPermM updColsM && any (`isMutable` viM) [viIsInsertable, viIsUpdatable, viIsDeletable] -- table obj - selObjM = mkTableObj tn <$> selFldsM + selObjM = mkTableObj tn descM <$> selFldsM -- aggregate objs and order by inputs (aggObjs, aggOrdByInps) = case selPermM of @@ -1403,7 +1389,6 @@ mkGCtxRole' tn insPermM selPermM updColsM getRootFldsRole' :: QualifiedTable - -> Maybe PGDescription -> [PGCol] -> [ConstraintName] -> FieldInfoMap @@ -1414,7 +1399,7 @@ getRootFldsRole' -> Maybe (AnnBoolExpPartialSQL, [T.Text]) -- delete filter -> Maybe ViewInfo -> RootFlds -getRootFldsRole' tn descM primCols constraints fields funcs insM selM updM delM viM = +getRootFldsRole' tn primCols constraints fields funcs insM selM updM delM viM = RootFlds mFlds where allCols = getCols fields @@ -1440,17 +1425,17 @@ getRootFldsRole' tn descM primCols constraints fields funcs insM selM updM delM getInsDet (hdrs, upsertPerm) = let isUpsertable = upsertable constraints upsertPerm $ isJust viM in ( OCInsert $ InsOpCtx tn $ hdrs `union` maybe [] (\(_, _, _, x) -> x) updM - , Right $ mkInsMutFld tn isUpsertable descM + , Right $ mkInsMutFld tn isUpsertable ) getUpdDet (updCols, preSetCols, updFltr, hdrs) = ( OCUpdate $ UpdOpCtx tn hdrs updFltr preSetCols allCols - , Right $ mkUpdMutFld tn (getColInfos updCols colInfos) descM + , Right $ mkUpdMutFld tn $ getColInfos updCols colInfos ) getDelDet (delFltr, hdrs) = ( OCDelete $ DelOpCtx tn hdrs delFltr allCols - , Right $ mkDelMutFld tn descM + , Right $ mkDelMutFld tn ) getSelDet (selFltr, pLimit, hdrs, _) = selFldHelper OCSelect mkSelFld selFltr pLimit hdrs @@ -1461,7 +1446,7 @@ getRootFldsRole' tn descM primCols constraints fields funcs insM selM updM delM selFldHelper f g pFltr pLimit hdrs = ( f $ SelOpCtx tn hdrs pFltr pLimit - , Left $ g tn descM + , Left $ g tn ) getPKeySelDet Nothing _ = Nothing @@ -1469,7 +1454,7 @@ getRootFldsRole' tn descM primCols constraints fields funcs insM selM updM delM getPKeySelDet (Just (selFltr, _, hdrs, _)) pCols = Just ( OCSelectPkey $ SelPkOpCtx tn hdrs selFltr $ mapFromL (mkColName . pgiName) pCols - , Left $ mkSelFldPKey tn pCols descM + , Left $ mkSelFldPKey tn pCols ) getFuncQueryFlds (selFltr, pLimit, hdrs, _) = @@ -1599,9 +1584,9 @@ mkGCtxRole tableCache tn descM fields pCols constraints funcs viM role permInfo let insPermM = snd <$> tabInsInfoM insCtxM = fst <$> tabInsInfoM updColsM = filterColInfos . upiCols <$> _permUpd permInfo - tyAgg = mkGCtxRole' tn insPermM selPermM updColsM + tyAgg = mkGCtxRole' tn descM insPermM selPermM updColsM (void $ _permDel permInfo) pColInfos constraints viM funcs - rootFlds = getRootFldsRole tn descM pCols constraints fields funcs viM permInfo + rootFlds = getRootFldsRole tn pCols constraints fields funcs viM permInfo insCtxMap = maybe Map.empty (Map.singleton tn) insCtxM return (tyAgg, rootFlds, insCtxMap) where @@ -1613,7 +1598,6 @@ mkGCtxRole tableCache tn descM fields pCols constraints funcs viM role permInfo getRootFldsRole :: QualifiedTable - -> Maybe PGDescription -> [PGCol] -> [ConstraintName] -> FieldInfoMap @@ -1621,8 +1605,8 @@ getRootFldsRole -> Maybe ViewInfo -> RolePermInfo -> RootFlds -getRootFldsRole tn descM pCols constraints fields funcs viM (RolePermInfo insM selM updM delM) = - getRootFldsRole' tn descM pCols constraints fields funcs +getRootFldsRole tn pCols constraints fields funcs viM (RolePermInfo insM selM updM delM) = + getRootFldsRole' tn pCols constraints fields funcs (mkIns <$> insM) (mkSel <$> selM) (mkUpd <$> updM) (mkDel <$> delM) viM @@ -1648,7 +1632,7 @@ mkGCtxMapTable tableCache funcCache tabInfo = do m <- Map.traverseWithKey (mkGCtxRole tableCache tn descM fields pkeyCols validConstraints tabFuncs viewInfo) rolePerms adminInsCtx <- mkAdminInsCtx tn tableCache fields - let adminCtx = mkGCtxRole' tn (Just (colInfos, icRelations adminInsCtx)) + let adminCtx = mkGCtxRole' tn descM (Just (colInfos, icRelations adminInsCtx)) (Just (True, selFlds)) (Just colInfos) (Just ()) pkeyColInfos validConstraints viewInfo tabFuncs adminInsCtxMap = Map.singleton tn adminInsCtx @@ -1665,7 +1649,7 @@ mkGCtxMapTable tableCache funcCache tabInfo = do FIColumn pgColInfo -> Left pgColInfo FIRelationship relInfo -> Right (relInfo, True, noFilter, Nothing, isRelNullable fields relInfo) adminRootFlds = - getRootFldsRole' tn descM pkeyCols validConstraints fields tabFuncs + getRootFldsRole' tn pkeyCols validConstraints fields tabFuncs (Just ([], True)) (Just (noFilter, Nothing, [], True)) (Just (validColNames, mempty, noFilter, [])) (Just (noFilter, [])) viewInfo From 23baa47e7e540671edd78b7bc47b9df395d03ef4 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Thu, 1 Aug 2019 15:49:00 +0530 Subject: [PATCH 09/12] capture functions' description update in run_sql --- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 7 ++++--- .../src-lib/Hasura/RQL/Types/SchemaCache.hs | 19 ++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index 271c4d938aa11..107f2480cfe4b 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -553,10 +553,11 @@ execWithMDCheck (RunSQL t cascade _) = do delFunctionFromCache qf -- Process altered functions - forM_ alteredFuncs $ \(qf, newTy, _) -> + forM_ alteredFuncs $ \(qf, newTy, newDesc) -> do when (newTy == FTVOLATILE) $ - throw400 NotSupported $ - "type of function " <> qf <<> " is altered to \"VOLATILE\" which is not supported now" + throw400 NotSupported $ "type of function " <> qf + <<> " is altered to \"VOLATILE\" which is not supported now" + updateFunctionDescription qf newDesc -- update the schema cache and hdb_catalog with the changes reloadRequired <- processSchemaChanges schemaDiff diff --git a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs index ec7429b069d76..499a5f4c7fca5 100644 --- a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs +++ b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs @@ -98,6 +98,7 @@ module Hasura.RQL.Types.SchemaCache , addFunctionToCache , askFunctionInfo , delFunctionFromCache + , updateFunctionDescription , replaceAllowlist ) where @@ -690,17 +691,25 @@ delFunctionFromCache :: (QErrM m, CacheRWM m) => QualifiedFunction -> m () delFunctionFromCache qf = do + void $ askFunctionInfo qf sc <- askSchemaCache let functionCache = scFunctions sc - case M.lookup qf functionCache of - Nothing -> throw500 $ "function does not exist in cache " <>> qf - Just _ -> do - let newFunctionCache = M.delete qf functionCache - writeSchemaCache $ sc {scFunctions = newFunctionCache} + newFunctionCache = M.delete qf functionCache + writeSchemaCache $ sc {scFunctions = newFunctionCache} modDepMapInCache (removeFromDepMap objId) where objId = SOFunction qf +updateFunctionDescription + :: (QErrM m, CacheRWM m) + => QualifiedFunction -> Maybe PGDescription -> m () +updateFunctionDescription qf descM = do + fi <- askFunctionInfo qf + sc <- askSchemaCache + let newFuncInfo = fi{fiDescription = descM} + newFuncCache = M.insert qf newFuncInfo $ scFunctions sc + writeSchemaCache sc{scFunctions = newFuncCache} + addPermToCache :: (QErrM m, CacheRWM m) => QualifiedTable From 43ef44ce1e44fc76397afc65f7053cead00ed6b8 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Mon, 5 Aug 2019 15:03:50 +0530 Subject: [PATCH 10/12] fix table_meta.sql --- server/src-rsr/table_meta.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src-rsr/table_meta.sql b/server/src-rsr/table_meta.sql index 9970cab254319..5e203c8c2e5a7 100644 --- a/server/src-rsr/table_meta.sql +++ b/server/src-rsr/table_meta.sql @@ -16,7 +16,7 @@ FROM FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace as n ON c.relnamespace = n.oid - LEFT JOIN pg_catalog.pg_description pd on c.oid = pd.objoid + LEFT JOIN pg_catalog.pg_description pd on (c.oid = pd.objoid and pd.objsubid = 0) ) t LEFT OUTER JOIN ( SELECT From 10f2ec0602e09749d7ae6e31c229ea402f078b6a Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Wed, 4 Sep 2019 18:38:00 +0530 Subject: [PATCH 11/12] fix table descriptions are not capturing --- server/src-lib/Hasura/RQL/DDL/Schema.hs | 2 +- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 4 ++-- server/src-lib/Hasura/RQL/Types/Catalog.hs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src-lib/Hasura/RQL/DDL/Schema.hs b/server/src-lib/Hasura/RQL/DDL/Schema.hs index aeefb130944af..980392a2fe0bb 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema.hs @@ -82,7 +82,7 @@ runRunSQL (RunSQL t cascade mChkMDCnstcy) = do isAltrDropReplace = either throwErr return . matchRegex regex False where throwErr s = throw500 $ "compiling regex failed: " <> T.pack s - regex = "alter|drop|replace|create function" + regex = "alter|drop|replace|create function|comment on" data RunSQLRes = RunSQLRes diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index f02ba3ef534cc..3d07037201b7c 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -279,11 +279,11 @@ buildTableCache = processTableCache <=< buildRawTableCache -- Step 1: Build the raw table cache from metadata information. buildRawTableCache :: [CatalogTable] -> m (TableCache PGRawColumnInfo) buildRawTableCache catalogTables = fmap (M.fromList . catMaybes) . for catalogTables $ - \(CatalogTable name isSystemDefined isEnum maybeDesc maybeInfo) -> withTable name $ do + \(CatalogTable name isSystemDefined isEnum maybeInfo) -> withTable name $ do catalogInfo <- onNothing maybeInfo $ throw400 NotExists $ "no such table/view exists in postgres: " <>> name - let CatalogTableInfo columns constraints primaryKeyColumnNames viewInfo = catalogInfo + let CatalogTableInfo columns constraints primaryKeyColumnNames viewInfo maybeDesc = catalogInfo columnFields = M.fromList . flip map columns $ \column -> (fromPGCol $ prciName column, FIColumn column) diff --git a/server/src-lib/Hasura/RQL/Types/Catalog.hs b/server/src-lib/Hasura/RQL/Types/Catalog.hs index 2a200e5c40972..6c5d1238402c3 100644 --- a/server/src-lib/Hasura/RQL/Types/Catalog.hs +++ b/server/src-lib/Hasura/RQL/Types/Catalog.hs @@ -34,6 +34,7 @@ data CatalogTableInfo , _ctiConstraints :: ![ConstraintName] , _ctiPrimaryKeyColumns :: ![PGCol] , _ctiViewInfo :: !(Maybe ViewInfo) + , _ctiDescription :: !(Maybe PGDescription) } deriving (Show, Eq) $(deriveJSON (aesonDrop 4 snakeCase) ''CatalogTableInfo) @@ -42,7 +43,6 @@ data CatalogTable { _ctName :: !QualifiedTable , _ctIsSystemDefined :: !Bool , _ctIsEnum :: !Bool - , _ctDescription :: !(Maybe PGDescription) , _ctInfo :: !(Maybe CatalogTableInfo) } deriving (Show, Eq) $(deriveJSON (aesonDrop 3 snakeCase) ''CatalogTable) From 411101992f787cd19bbe5f53482876522c0e1e60 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Mon, 16 Sep 2019 11:31:09 +0530 Subject: [PATCH 12/12] fix typo 'psuedo'; rename it to 'pseudo' in server code --- server/src-lib/Hasura/RQL/DDL/Schema/Function.hs | 2 +- server/src-rsr/initialise.sql | 2 +- server/src-rsr/migrate_from_12_to_13.sql | 2 +- server/src-rsr/migrate_from_21_to_22.sql | 2 +- server/src-rsr/migrate_from_22_to_23.sql | 2 +- server/src-rsr/migrate_from_7_to_8.sql | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs index 0cff2a2a782c9..343f2e0562df8 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs @@ -30,7 +30,7 @@ data PGTypType | PTDOMAIN | PTENUM | PTRANGE - | PTPSUEDO + | PTPSEUDO deriving (Show, Eq) $(deriveJSON defaultOptions{constructorTagModifier = drop 2} ''PGTypType) diff --git a/server/src-rsr/initialise.sql b/server/src-rsr/initialise.sql index 4b901f2a9a307..5465fb1b736fd 100644 --- a/server/src-rsr/initialise.sql +++ b/server/src-rsr/initialise.sql @@ -344,7 +344,7 @@ SELECT WHEN ((rt.typtype) :: text = ('d' :: character(1)) :: text) THEN 'DOMAIN' :: text WHEN ((rt.typtype) :: text = ('e' :: character(1)) :: text) THEN 'ENUM' :: text WHEN ((rt.typtype) :: text = ('r' :: character(1)) :: text) THEN 'RANGE' :: text - WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSUEDO' :: text + WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSEUDO' :: text ELSE NULL :: text END AS return_type_type, p.proretset AS returns_set, diff --git a/server/src-rsr/migrate_from_12_to_13.sql b/server/src-rsr/migrate_from_12_to_13.sql index 7ab034f7ee1d3..437ed0819d070 100644 --- a/server/src-rsr/migrate_from_12_to_13.sql +++ b/server/src-rsr/migrate_from_12_to_13.sql @@ -33,7 +33,7 @@ SELECT WHEN ((rt.typtype) :: text = ('d' :: character(1)) :: text) THEN 'DOMAIN' :: text WHEN ((rt.typtype) :: text = ('e' :: character(1)) :: text) THEN 'ENUM' :: text WHEN ((rt.typtype) :: text = ('r' :: character(1)) :: text) THEN 'RANGE' :: text - WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSUEDO' :: text + WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSEUDO' :: text ELSE NULL :: text END AS return_type_type, p.proretset AS returns_set, diff --git a/server/src-rsr/migrate_from_21_to_22.sql b/server/src-rsr/migrate_from_21_to_22.sql index 4e5ca9db64e67..854262b0b2b30 100644 --- a/server/src-rsr/migrate_from_21_to_22.sql +++ b/server/src-rsr/migrate_from_21_to_22.sql @@ -36,7 +36,7 @@ SELECT WHEN ((rt.typtype) :: text = ('d' :: character(1)) :: text) THEN 'DOMAIN' :: text WHEN ((rt.typtype) :: text = ('e' :: character(1)) :: text) THEN 'ENUM' :: text WHEN ((rt.typtype) :: text = ('r' :: character(1)) :: text) THEN 'RANGE' :: text - WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSUEDO' :: text + WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSEUDO' :: text ELSE NULL :: text END AS return_type_type, p.proretset AS returns_set, diff --git a/server/src-rsr/migrate_from_22_to_23.sql b/server/src-rsr/migrate_from_22_to_23.sql index 5e809cf0b19a2..fde7389dec7d8 100644 --- a/server/src-rsr/migrate_from_22_to_23.sql +++ b/server/src-rsr/migrate_from_22_to_23.sql @@ -163,7 +163,7 @@ SELECT WHEN ((rt.typtype) :: text = ('d' :: character(1)) :: text) THEN 'DOMAIN' :: text WHEN ((rt.typtype) :: text = ('e' :: character(1)) :: text) THEN 'ENUM' :: text WHEN ((rt.typtype) :: text = ('r' :: character(1)) :: text) THEN 'RANGE' :: text - WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSUEDO' :: text + WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSEUDO' :: text ELSE NULL :: text END AS return_type_type, p.proretset AS returns_set, diff --git a/server/src-rsr/migrate_from_7_to_8.sql b/server/src-rsr/migrate_from_7_to_8.sql index fb8455043a3ac..c088a00e1a1bc 100644 --- a/server/src-rsr/migrate_from_7_to_8.sql +++ b/server/src-rsr/migrate_from_7_to_8.sql @@ -42,7 +42,7 @@ SELECT WHEN ((rt.typtype) :: text = ('d' :: character(1)) :: text) THEN 'DOMAIN' :: text WHEN ((rt.typtype) :: text = ('e' :: character(1)) :: text) THEN 'ENUM' :: text WHEN ((rt.typtype) :: text = ('r' :: character(1)) :: text) THEN 'RANGE' :: text - WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSUEDO' :: text + WHEN ((rt.typtype) :: text = ('p' :: character(1)) :: text) THEN 'PSEUDO' :: text ELSE NULL :: text END AS return_type_type, p.proretset AS returns_set,