From 6d0de6bf18c2bc3717fa5350395ab5f5f7113286 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Wed, 7 Aug 2019 12:03:53 +0530 Subject: [PATCH 1/5] allow altering type of a column iff session vars are defined in permissions --- server/src-lib/Hasura/RQL/DDL/Permission.hs | 59 +++++++++++++++++-- .../src-lib/Hasura/RQL/DDL/Schema/Rename.hs | 14 +---- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 23 +++++++- server/src-lib/Hasura/RQL/DML/Count.hs | 11 ---- server/src-lib/Hasura/RQL/DML/Delete.hs | 11 ---- server/src-lib/Hasura/RQL/DML/Insert.hs | 8 --- server/src-lib/Hasura/RQL/DML/Select.hs | 42 ------------- server/src-lib/Hasura/RQL/DML/Update.hs | 13 ---- server/src-lib/Hasura/RQL/GBoolExp.hs | 51 ++++++++++++++-- server/src-lib/Hasura/RQL/Types/BoolExp.hs | 6 ++ 10 files changed, 128 insertions(+), 110 deletions(-) diff --git a/server/src-lib/Hasura/RQL/DDL/Permission.hs b/server/src-lib/Hasura/RQL/DDL/Permission.hs index 98d2d07c821c2..d06b12f5d57f2 100644 --- a/server/src-lib/Hasura/RQL/DDL/Permission.hs +++ b/server/src-lib/Hasura/RQL/DDL/Permission.hs @@ -44,6 +44,9 @@ module Hasura.RQL.DDL.Permission , SetPermComment(..) , runSetPermComment + + , rebuildPermInfo + , fetchPermDef ) where import Hasura.EncJSON @@ -108,14 +111,14 @@ procSetObj => TableInfo -> Maybe ColVals -> m (PreSetColsPartial, [Text], [SchemaDependency]) procSetObj ti mObj = do - setColsSQL <- withPathK "set" $ - fmap HM.fromList $ forM (HM.toList setObj) $ \(pgCol, val) -> do + (setColTups, deps) <- withPathK "set" $ + fmap unzip $ forM (HM.toList setObj) $ \(pgCol, val) -> do ty <- askPGType fieldInfoMap pgCol $ "column " <> pgCol <<> " not found in table " <>> tn sqlExp <- valueParser (PgTypeSimple ty) val - return (pgCol, sqlExp) - let deps = map (mkColDep "on_type" tn . fst) $ HM.toList setColsSQL - return (setColsSQL, depHeaders, deps) + let dep = mkColDep (getDepReason sqlExp) tn pgCol + return ((pgCol, sqlExp), dep) + return (HM.fromList setColTups, depHeaders, deps) where fieldInfoMap = tiFieldInfoMap ti tn = tiName ti @@ -123,6 +126,8 @@ procSetObj ti mObj = do depHeaders = getDepHeadersFromVal $ Object $ HM.fromList $ map (first getPGColTxt) $ HM.toList setObj + getDepReason = bool "sess_var" "on_type" . isStaticValue + buildInsPermInfo :: (QErrM m, CacheRM m) => TableInfo @@ -437,3 +442,47 @@ purgePerm qt rn pt = where dp :: DropPerm a dp = DropPerm qt rn + +rebuildPermInfo + :: (QErrM m, CacheRWM m, MonadTx m) + => QualifiedTable -> RoleName -> PermType -> m () +rebuildPermInfo qt rn pt = do + (pDef, comment) <- liftTx $ fetchPermDef qt rn pt + case pt of + PTInsert -> do + perm <- decodeValue pDef + updatePerm PAInsert $ PermDef rn perm comment + PTSelect -> do + perm <- decodeValue pDef + updatePerm PASelect $ PermDef rn perm comment + PTUpdate -> do + perm <- decodeValue pDef + updatePerm PAUpdate $ PermDef rn perm comment + PTDelete -> do + perm <- decodeValue pDef + updatePerm PADelete $ PermDef rn perm comment + + where + updatePerm :: (QErrM m, CacheRWM m, IsPerm a) + => PermAccessor (PermInfo a) -> PermDef a -> m () + updatePerm pa perm = do + delPermFromCache pa rn qt + tabInfo <- askTabInfo qt + (permInfo, deps) <- addPermP1 tabInfo perm + addPermToCache qt rn pa permInfo deps + +fetchPermDef + :: QualifiedTable + -> RoleName + -> PermType + -> Q.TxE QErr (Value, Maybe T.Text) +fetchPermDef (QualifiedObject sn tn) rn pt = + (first Q.getAltJ . Q.getRow) <$> Q.withQE defaultTxErrorHandler + [Q.sql| + SELECT perm_def::json, comment + FROM hdb_catalog.hdb_permission + WHERE table_schema = $1 + AND table_name = $2 + AND role_name = $3 + AND perm_type = $4 + |] (sn, tn, rn, permTypeToCode pt) True diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Rename.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Rename.hs index 059bab4d671ce..44f64fd5d8dee 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Rename.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Rename.hs @@ -169,7 +169,7 @@ updateArrRelDef qt rn (oldQT, newQT) = do updatePermFlds :: (MonadTx m, CacheRM m) => QualifiedTable -> RoleName -> PermType -> RenameField -> m () updatePermFlds refQT rn pt rf = do - Q.AltJ pDef <- liftTx fetchPermDef + pDef <- fmap fst $ liftTx $ fetchPermDef refQT rn pt case pt of PTInsert -> do perm <- decodeValue pDef @@ -183,18 +183,6 @@ updatePermFlds refQT rn pt rf = do PTDelete -> do perm <- decodeValue pDef updateDelPermFlds refQT rf rn perm - where - QualifiedObject sn tn = refQT - fetchPermDef = - runIdentity . Q.getRow <$> - Q.withQE defaultTxErrorHandler [Q.sql| - SELECT perm_def::json - FROM hdb_catalog.hdb_permission - WHERE table_schema = $1 - AND table_name = $2 - AND role_name = $3 - AND perm_type = $4 - |] (sn, tn, rn, permTypeToCode pt) True updateInsPermFlds :: (MonadTx m, CacheRM m) diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index e6b7452aa5edc..942450560a85f 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -189,18 +189,35 @@ processTableChanges ti tableDiff = do if | oColName /= nColName -> do renameColInCatalog oColName nColName tn ti return True + | oColTy /= nColTy -> do let colId = SOTableObj tn $ TOCol oColName - depObjs = getDependentObjsWith (== "on_type") sc colId - unless (null depObjs) $ throw400 DependencyError $ + typeDepObjs = getDependentObjsWith (== "on_type") sc colId + + -- Raise exception if any objects found which are dependant on column type + unless (null typeDepObjs) $ throw400 DependencyError $ "cannot change type of column " <> oColName <<> " in table " <> tn <<> " because of the following dependencies : " <> - reportSchemaObjs depObjs + reportSchemaObjs typeDepObjs + + -- Update column type in cache updColInCache nColName npci tn + + -- If any dependant permissions found with the column whose type + -- being altered is provided with a session variable, + -- then rebuild permission info and update the cache + let sessVarDepObjs = getDependentObjsWith (== "sess_var") sc colId + forM_ sessVarDepObjs $ \objId -> + case objId of + SOTableObj qt (TOPerm rn pt) -> rebuildPermInfo qt rn pt + _ -> throw500 + "unexpected schema dependency found for altering column type" return False + | oNullable /= nNullable -> do updColInCache nColName npci tn return False + | otherwise -> return False delTableAndDirectDeps diff --git a/server/src-lib/Hasura/RQL/DML/Count.hs b/server/src-lib/Hasura/RQL/DML/Count.hs index 3a50da9c4e691..8289f350afc0f 100644 --- a/server/src-lib/Hasura/RQL/DML/Count.hs +++ b/server/src-lib/Hasura/RQL/DML/Count.hs @@ -1,6 +1,5 @@ module Hasura.RQL.DML.Count ( CountQueryP1(..) - , getCountDeps , validateCountQWith , validateCountQ , runCount @@ -30,16 +29,6 @@ data CountQueryP1 , cqp1Distinct :: !(Maybe [PGCol]) } deriving (Show, Eq) -getCountDeps - :: CountQueryP1 -> [SchemaDependency] -getCountDeps (CountQueryP1 tn (_, mWc) mDistCols) = - mkParentDep tn - : fromMaybe [] whereDeps - <> fromMaybe [] distDeps - where - distDeps = map (mkColDep "untyped" tn) <$> mDistCols - whereDeps = getBoolExpDeps tn <$> mWc - mkSQLCount :: CountQueryP1 -> S.Select mkSQLCount (CountQueryP1 tn (permFltr, mWc) mDistCols) = diff --git a/server/src-lib/Hasura/RQL/DML/Delete.hs b/server/src-lib/Hasura/RQL/DML/Delete.hs index 79fca452cdb56..244c88aaa3dbe 100644 --- a/server/src-lib/Hasura/RQL/DML/Delete.hs +++ b/server/src-lib/Hasura/RQL/DML/Delete.hs @@ -5,7 +5,6 @@ module Hasura.RQL.DML.Delete , traverseAnnDel , AnnDel , deleteQueryToTx - , getDeleteDeps , runDelete ) where @@ -58,16 +57,6 @@ mkDeleteCTE (AnnDel tn (fltr, wc) _ _) = tableFltr = Just $ S.WhereFrag $ toSQLBoolExp (S.QualTable tn) $ andAnnBoolExps fltr wc -getDeleteDeps - :: AnnDel -> [SchemaDependency] -getDeleteDeps (AnnDel tn (_, wc) mutFlds allCols) = - mkParentDep tn : allColDeps <> whereDeps <> retDeps - where - whereDeps = getBoolExpDeps tn wc - allColDeps = map (mkColDep "on_type" tn . pgiName) allCols - retDeps = map (mkColDep "untyped" tn . fst) $ - pgColsFromMutFlds mutFlds - validateDeleteQWith :: (UserInfoM m, QErrM m, CacheRM m) => SessVarBldr m diff --git a/server/src-lib/Hasura/RQL/DML/Insert.hs b/server/src-lib/Hasura/RQL/DML/Insert.hs index 6424fb14d0f63..bd0260ae2bf84 100644 --- a/server/src-lib/Hasura/RQL/DML/Insert.hs +++ b/server/src-lib/Hasura/RQL/DML/Insert.hs @@ -62,14 +62,6 @@ toSQLConflict conflict = case conflict of Column pgCols -> S.SQLColumn pgCols Constraint cn -> S.SQLConstraint cn -getInsertDeps - :: InsertQueryP1 -> [SchemaDependency] -getInsertDeps (InsertQueryP1 tn _ _ _ _ mutFlds _) = - mkParentDep tn : retDeps - where - retDeps = map (mkColDep "untyped" tn . fst) $ - pgColsFromMutFlds mutFlds - convObj :: (UserInfoM m, QErrM m) => (PGColType -> Value -> m S.SQLExp) diff --git a/server/src-lib/Hasura/RQL/DML/Select.hs b/server/src-lib/Hasura/RQL/DML/Select.hs index c3c8dd58182c9..919e4ad08c403 100644 --- a/server/src-lib/Hasura/RQL/DML/Select.hs +++ b/server/src-lib/Hasura/RQL/DML/Select.hs @@ -5,7 +5,6 @@ module Hasura.RQL.DML.Select , mkFuncSelectSimple , mkFuncSelectAgg , convSelectQuery - , getSelectDeps , asSingleRowJsonResp , module Hasura.RQL.DML.Select.Internal , runSelect @@ -24,7 +23,6 @@ import Hasura.EncJSON import Hasura.Prelude import Hasura.RQL.DML.Internal import Hasura.RQL.DML.Select.Internal -import Hasura.RQL.GBoolExp import Hasura.RQL.Types import Hasura.SQL.Types @@ -249,46 +247,6 @@ convExtRel fieldInfoMap relName mAlias selQ sessVarBldr prepValBldr = do , " can't be used" ] -partAnnFlds - :: [AnnFld] - -> ([(PGCol, PGColType)], [Either ObjSel ArrSel]) -partAnnFlds flds = - partitionEithers $ catMaybes $ flip map flds $ \case - FCol c _ -> Just $ Left (pgiName c, pgiType c) - FObj o -> Just $ Right $ Left o - FArr a -> Just $ Right $ Right a - FExp _ -> Nothing - -getSelectDeps - :: AnnSimpleSel - -> [SchemaDependency] -getSelectDeps (AnnSelG flds tabFrm _ tableArgs _) = - mkParentDep tn - : fromMaybe [] whereDeps - <> colDeps - <> relDeps - <> nestedDeps - where - TableFrom tn _ = tabFrm - annWc = _taWhere tableArgs - (sCols, rCols) = partAnnFlds $ map snd flds - (objSels, arrSels) = partitionEithers rCols - colDeps = map (mkColDep "untyped" tn . fst) sCols - relDeps = map mkRelDep $ map aarName objSels - <> mapMaybe getRelName arrSels - nestedDeps = concatMap getSelectDeps $ map aarAnnSel objSels - <> mapMaybe getAnnSel arrSels - whereDeps = getBoolExpDeps tn <$> annWc - mkRelDep rn = - SchemaDependency (SOTableObj tn (TORel rn)) "untyped" - - -- ignore aggregate selections to calculate schema deps - getRelName (ASSimple aar) = Just $ aarName aar - getRelName (ASAgg _) = Nothing - - getAnnSel (ASSimple aar) = Just $ aarAnnSel aar - getAnnSel (ASAgg _) = Nothing - convSelectQuery :: (UserInfoM m, QErrM m, CacheRM m, HasSQLGenCtx m) => SessVarBldr m diff --git a/server/src-lib/Hasura/RQL/DML/Update.hs b/server/src-lib/Hasura/RQL/DML/Update.hs index 7069d5f322f65..9bb6e2c9d2d78 100644 --- a/server/src-lib/Hasura/RQL/DML/Update.hs +++ b/server/src-lib/Hasura/RQL/DML/Update.hs @@ -5,7 +5,6 @@ module Hasura.RQL.DML.Update , traverseAnnUpd , AnnUpd , updateQueryToTx - , getUpdateDeps , runUpdate ) where @@ -66,18 +65,6 @@ mkUpdateCTE (AnnUpd tn setExps (permFltr, wc) _ _) = tableFltr = Just $ S.WhereFrag $ toSQLBoolExp (S.QualTable tn) $ andAnnBoolExps permFltr wc -getUpdateDeps - :: AnnUpd - -> [SchemaDependency] -getUpdateDeps (AnnUpd tn setExps (_, wc) mutFlds allCols) = - mkParentDep tn : colDeps <> allColDeps <> whereDeps <> retDeps - where - colDeps = map (mkColDep "on_type" tn . fst) setExps - allColDeps = map (mkColDep "on_type" tn . pgiName) allCols - whereDeps = getBoolExpDeps tn wc - retDeps = map (mkColDep "untyped" tn . fst) $ - pgColsFromMutFlds mutFlds - convInc :: (QErrM m) => (PGColType -> Value -> m S.SQLExp) diff --git a/server/src-lib/Hasura/RQL/GBoolExp.hs b/server/src-lib/Hasura/RQL/GBoolExp.hs index 59f082d6160bf..b261e9619c562 100644 --- a/server/src-lib/Hasura/RQL/GBoolExp.hs +++ b/server/src-lib/Hasura/RQL/GBoolExp.hs @@ -436,19 +436,62 @@ mkColCompExp qual lhsCol = mkCompExp (mkQCol lhsCol) sqlAll = foldr (S.BEBin S.AndOp) (S.BELit True) pgTypeToAnnType = S.TypeAnn . T.pack . show -getColExpDeps :: QualifiedTable -> AnnBoolExpFld a -> [SchemaDependency] +hasStaticExp :: OpExpG PartialSQLExp -> Bool +hasStaticExp = \case + ACast casts -> any hasStaticExp $ concat $ M.elems casts + + AEQ _ val -> isStaticValue val + ANE _ val -> isStaticValue val + + AIN val -> isStaticValue val + ANIN val -> isStaticValue val + AGT val -> isStaticValue val + ALT val -> isStaticValue val + AGTE val -> isStaticValue val + ALTE val -> isStaticValue val + + ALIKE val -> isStaticValue val + ANLIKE val -> isStaticValue val + AILIKE val -> isStaticValue val + ANILIKE val -> isStaticValue val + + ASIMILAR val -> isStaticValue val + ANSIMILAR val -> isStaticValue val + + AContains val -> isStaticValue val + AContainedIn val -> isStaticValue val + AHasKey val -> isStaticValue val + AHasKeysAny val -> isStaticValue val + AHasKeysAll val -> isStaticValue val + + ASTContains val -> isStaticValue val + ASTCrosses val -> isStaticValue val + ASTEquals val -> isStaticValue val + ASTIntersects val -> isStaticValue val + ASTOverlaps val -> isStaticValue val + ASTTouches val -> isStaticValue val + ASTWithin val -> isStaticValue val + ASTDWithinGeom (DWithinGeomOp r val) -> any isStaticValue [r, val] + ASTDWithinGeog (DWithinGeogOp r val sph) -> any isStaticValue [r, val, sph] + + _ -> False + +getColExpDeps + :: QualifiedTable -> AnnBoolExpFldPartialSQL -> [SchemaDependency] getColExpDeps tn = \case AVCol colInfo opExps -> let cn = pgiName colInfo + colDepReason = bool "sess_var" "on_type" $ any hasStaticExp opExps + colDep = mkColDep colDepReason tn cn depColsInOpExp = mapMaybe opExpDepCol opExps - allDepCols = cn:depColsInOpExp - in map (mkColDep "on_type" tn) allDepCols + colDepsInOpExp = map (mkColDep "on_type" tn) depColsInOpExp + in colDep:colDepsInOpExp AVRel relInfo relBoolExp -> let rn = riName relInfo relTN = riRTable relInfo pd = SchemaDependency (SOTableObj tn (TORel rn)) "on_type" in pd : getBoolExpDeps relTN relBoolExp -getBoolExpDeps :: QualifiedTable -> AnnBoolExp a -> [SchemaDependency] +getBoolExpDeps :: QualifiedTable -> AnnBoolExpPartialSQL -> [SchemaDependency] getBoolExpDeps tn = foldr (\annFld deps -> getColExpDeps tn annFld <> deps) [] diff --git a/server/src-lib/Hasura/RQL/Types/BoolExp.hs b/server/src-lib/Hasura/RQL/Types/BoolExp.hs index e558a89cdacac..d13d139f9afa8 100644 --- a/server/src-lib/Hasura/RQL/Types/BoolExp.hs +++ b/server/src-lib/Hasura/RQL/Types/BoolExp.hs @@ -20,6 +20,7 @@ module Hasura.RQL.Types.BoolExp , AnnBoolExpFldSQL , AnnBoolExpSQL , PartialSQLExp(..) + , isStaticValue , AnnBoolExpFldPartialSQL , AnnBoolExpPartialSQL @@ -303,3 +304,8 @@ instance ToJSON AnnBoolExpPartialSQL where opExpSToJSON :: OpExpG PartialSQLExp -> Value opExpSToJSON = object . pure . opExpToJPair toJSON + +isStaticValue :: PartialSQLExp -> Bool +isStaticValue = \case + PSESessVar _ _ -> False + PSESQLExp _ -> True From cc43a0df89974c22bdb89cbc7d8067baf20adaf9 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Wed, 7 Aug 2019 19:50:19 +0530 Subject: [PATCH 2/5] add tests --- server/tests-py/queries/v1/run_sql/setup.yaml | 37 +++++++++++++ .../v1/run_sql/sql_alter_test_bool_col.yaml | 11 ++++ .../queries/v1/run_sql/sql_alter_test_id.yaml | 52 +++++++++++++++++++ .../tests-py/queries/v1/run_sql/teardown.yaml | 1 + server/tests-py/test_v1_queries.py | 8 +++ 5 files changed, 109 insertions(+) create mode 100644 server/tests-py/queries/v1/run_sql/sql_alter_test_bool_col.yaml create mode 100644 server/tests-py/queries/v1/run_sql/sql_alter_test_id.yaml diff --git a/server/tests-py/queries/v1/run_sql/setup.yaml b/server/tests-py/queries/v1/run_sql/setup.yaml index 920e16d4ea6be..1a17c46f46fc5 100644 --- a/server/tests-py/queries/v1/run_sql/setup.yaml +++ b/server/tests-py/queries/v1/run_sql/setup.yaml @@ -20,6 +20,12 @@ args: ('article 1 by author 1', 'content for article 1', 1), ('article 2 by author 1', 'content for article 2', 1), ('article 1 by author 2', 'content for article 3', 2); + create table test( + id serial primary key, + name text not null, + bool_col boolean not null default false + ); + insert into test (name) values ('name_1'), ('name_2'); - type: track_table args: @@ -84,3 +90,34 @@ args: - content - author_id check: {} + +#test table +- type: track_table + args: + name: test + schema: public + +- type: create_select_permission + args: + table: test + role: user + permission: + columns: + - id + - name + filter: + id: X-Hasura-User-Id + bool_col: true + +- type: create_insert_permission + args: + table: test + role: user + permission: + columns: + - id + - name + check: + id: X-Hasura-User-Id + set: + bool_col: true diff --git a/server/tests-py/queries/v1/run_sql/sql_alter_test_bool_col.yaml b/server/tests-py/queries/v1/run_sql/sql_alter_test_bool_col.yaml new file mode 100644 index 0000000000000..d68aa693bfab6 --- /dev/null +++ b/server/tests-py/queries/v1/run_sql/sql_alter_test_bool_col.yaml @@ -0,0 +1,11 @@ +description: Alter bool_col column type in test table whose permissions are defined with static value +url: /v1/query +status: 400 +response: + path: "$.args" + error: 'cannot change type of column "bool_col" in table "test" because of the following dependencies : permission test.user.select, permission test.user.insert' + code: dependency-error +query: + type: run_sql + args: + sql: alter table test alter column bool_col set data type text; diff --git a/server/tests-py/queries/v1/run_sql/sql_alter_test_id.yaml b/server/tests-py/queries/v1/run_sql/sql_alter_test_id.yaml new file mode 100644 index 0000000000000..34ed22010f786 --- /dev/null +++ b/server/tests-py/queries/v1/run_sql/sql_alter_test_id.yaml @@ -0,0 +1,52 @@ +- description: Query data from test table + url: /v1/graphql + status: 200 + response: + data: + test: + - id: 1 + name: name_1 + bool_col: false + - id: 2 + name: name_2 + bool_col: false + query: + query: | + query { + test{ + id + name + bool_col + } + } + +- description: Alter the data type of id column + url: /v1/query + status: 200 + query: + type: run_sql + args: + sql: | + alter table test alter column id set data type text; + +- description: Query data from test table; now id column is of text type + url: /v1/graphql + status: 200 + response: + data: + test: + - id: '1' + name: name_1 + bool_col: false + - id: '2' + name: name_2 + bool_col: false + query: + query: | + query { + test{ + id + name + bool_col + } + } diff --git a/server/tests-py/queries/v1/run_sql/teardown.yaml b/server/tests-py/queries/v1/run_sql/teardown.yaml index 1f8e9525be3fd..983ca4f19729c 100644 --- a/server/tests-py/queries/v1/run_sql/teardown.yaml +++ b/server/tests-py/queries/v1/run_sql/teardown.yaml @@ -5,4 +5,5 @@ args: sql: | drop table article; drop table author; + drop table test; cascade: true diff --git a/server/tests-py/test_v1_queries.py b/server/tests-py/test_v1_queries.py index 180a340fdc1fb..f669de253d451 100644 --- a/server/tests-py/test_v1_queries.py +++ b/server/tests-py/test_v1_queries.py @@ -510,6 +510,14 @@ def test_sql_rename_columns_author(self, hge_ctx): def test_sql_rename_table_and_column(self, hge_ctx): check_query_f(hge_ctx, self.dir() + '/sql_rename_table_and_column.yaml') + def test_sql_alter_test_bool_col(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/sql_alter_test_bool_col.yaml') + hge_ctx.may_skip_test_teardown = True + + def test_sql_alter_test_id(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/sql_alter_test_id.yaml') + hge_ctx.may_skip_test_teardown = True + @classmethod def dir(cls): return "queries/v1/run_sql" From bfbea13dfb6dd83b28baac533bed2f4dc8682214 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Fri, 9 Aug 2019 15:35:57 +0530 Subject: [PATCH 3/5] use a sum type to define dependency reason --- server/src-lib/Hasura/RQL/DDL/EventTrigger.hs | 6 +-- server/src-lib/Hasura/RQL/DDL/Permission.hs | 8 ++-- server/src-lib/Hasura/RQL/DDL/Relationship.hs | 20 +++++----- .../src-lib/Hasura/RQL/DDL/Schema/Function.hs | 2 +- server/src-lib/Hasura/RQL/DDL/Schema/Table.hs | 5 ++- server/src-lib/Hasura/RQL/GBoolExp.hs | 6 +-- .../src-lib/Hasura/RQL/Types/SchemaCache.hs | 7 ++-- .../Hasura/RQL/Types/SchemaCacheTypes.hs | 39 ++++++++++++++++++- 8 files changed, 66 insertions(+), 27 deletions(-) diff --git a/server/src-lib/Hasura/RQL/DDL/EventTrigger.hs b/server/src-lib/Hasura/RQL/DDL/EventTrigger.hs index 45f15bec275b4..2a62a888116ee 100644 --- a/server/src-lib/Hasura/RQL/DDL/EventTrigger.hs +++ b/server/src-lib/Hasura/RQL/DDL/EventTrigger.hs @@ -258,7 +258,7 @@ subTableP2Setup qt (EventTriggerConf name def webhook webhookFromEnv rconf mhead webhookInfo <- getWebhookInfoFromConf webhookConf headerInfos <- getHeaderInfosFromConf headerConfs let eTrigInfo = EventTriggerInfo name def rconf webhookInfo headerInfos - tabDep = SchemaDependency (SOTable qt) "parent" + tabDep = SchemaDependency (SOTable qt) DRParent addEventTriggerToCache qt eTrigInfo (tabDep:getTrigDefDeps qt def) getTrigDefDeps :: QualifiedTable -> TriggerOpsDef -> [SchemaDependency] @@ -272,10 +272,10 @@ getTrigDefDeps qt (TriggerOpsDef mIns mUpd mDel _) = subsOpSpecDeps os = let cols = getColsFromSub $ sosColumns os colDeps = flip map cols $ \col -> - SchemaDependency (SOTableObj qt (TOCol col)) "column" + SchemaDependency (SOTableObj qt (TOCol col)) DRColumn payload = maybe [] getColsFromSub (sosPayload os) payloadDeps = flip map payload $ \col -> - SchemaDependency (SOTableObj qt (TOCol col)) "payload" + SchemaDependency (SOTableObj qt (TOCol col)) DRPayload in colDeps <> payloadDeps getColsFromSub sc = case sc of SubCStar -> [] diff --git a/server/src-lib/Hasura/RQL/DDL/Permission.hs b/server/src-lib/Hasura/RQL/DDL/Permission.hs index d06b12f5d57f2..c5ac70dd5ca24 100644 --- a/server/src-lib/Hasura/RQL/DDL/Permission.hs +++ b/server/src-lib/Hasura/RQL/DDL/Permission.hs @@ -126,7 +126,7 @@ procSetObj ti mObj = do depHeaders = getDepHeadersFromVal $ Object $ HM.fromList $ map (first getPGColTxt) $ HM.toList setObj - getDepReason = bool "sess_var" "on_type" . isStaticValue + getDepReason = bool DRSessionVariable DROnType . isStaticValue buildInsPermInfo :: (QErrM m, CacheRM m) @@ -143,7 +143,7 @@ buildInsPermInfo tabInfo (PermDef rn (InsPerm chk set mCols) _) = askPGType fieldInfoMap col "" let fltrHeaders = getDependentHeaders chk reqHdrs = fltrHeaders `union` setHdrs - insColDeps = map (mkColDep "untyped" tn) insCols + insColDeps = map (mkColDep DRUntyped tn) insCols deps = mkParentDep tn : beDeps ++ setColDeps ++ insColDeps insColsWithoutPresets = insCols \\ HM.keys setColsSQL return (InsPermInfo (HS.fromList insColsWithoutPresets) vn be setColsSQL reqHdrs, deps) @@ -226,7 +226,7 @@ buildSelPermInfo tabInfo sp = do void $ withPathK "columns" $ indexedForM pgCols $ \pgCol -> askPGType fieldInfoMap pgCol autoInferredErr - let deps = mkParentDep tn : beDeps ++ map (mkColDep "untyped" tn) pgCols + let deps = mkParentDep tn : beDeps ++ map (mkColDep DRUntyped tn) pgCols depHeaders = getDependentHeaders $ spFilter sp mLimit = spLimit sp @@ -296,7 +296,7 @@ buildUpdPermInfo tabInfo (UpdPerm colSpec set fltr) = do void $ withPathK "columns" $ indexedForM updCols $ \updCol -> askPGType fieldInfoMap updCol relInUpdErr - let updColDeps = map (mkColDep "untyped" tn) updCols + let updColDeps = map (mkColDep DRUntyped tn) updCols deps = mkParentDep tn : beDeps ++ updColDeps ++ setColDeps depHeaders = getDependentHeaders fltr reqHeaders = depHeaders `union` setHeaders diff --git a/server/src-lib/Hasura/RQL/DDL/Relationship.hs b/server/src-lib/Hasura/RQL/DDL/Relationship.hs index 14bf0dc118b84..4995a4425d35b 100644 --- a/server/src-lib/Hasura/RQL/DDL/Relationship.hs +++ b/server/src-lib/Hasura/RQL/DDL/Relationship.hs @@ -111,20 +111,20 @@ objRelP2Setup qt fkeys (RelDef rn ru _) = do RUManual (ObjRelManualConfig rm) -> do let refqt = rmTable rm (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 + deps = map (\c -> SchemaDependency (SOTableObj qt $ TOCol c) DRLeftColumn) lCols + <> map (\c -> SchemaDependency (SOTableObj refqt $ TOCol c) DRRightColumn) rCols return (RelInfo rn ObjRel (zip lCols rCols) refqt True, deps) RUFKeyOn cn -> do -- TODO: validation should account for this too ForeignKey _ refqt _ consName colMap <- getRequiredFkey cn fkeys $ \fk -> _fkTable fk == qt - let deps = [ SchemaDependency (SOTableObj qt $ TOCons consName) "fkey" - , SchemaDependency (SOTableObj qt $ TOCol cn) "using_col" + let deps = [ SchemaDependency (SOTableObj qt $ TOCons consName) DRFkey + , SchemaDependency (SOTableObj qt $ TOCol cn) DRUsingColumn -- this needs to be added explicitly to handle the remote table -- being untracked. In this case, neither the using_col nor -- the constraint name will help. - , SchemaDependency (SOTable refqt) "remote_table" + , SchemaDependency (SOTable refqt) DRRemoteTable ] colMapping = HM.toList colMap void $ askTabInfo refqt @@ -186,19 +186,19 @@ arrRelP2Setup qt fkeys (RelDef rn ru _) = do RUManual (ArrRelManualConfig rm) -> do let refqt = rmTable rm (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 + deps = map (\c -> SchemaDependency (SOTableObj qt $ TOCol c) DRLeftColumn) lCols + <> map (\c -> SchemaDependency (SOTableObj refqt $ TOCol c) DRRightColumn) rCols return (RelInfo rn ArrRel (zip lCols rCols) refqt True, deps) RUFKeyOn (ArrRelUsingFKeyOn refqt refCol) -> do -- TODO: validation should account for this too ForeignKey _ _ _ consName colMap <- getRequiredFkey refCol fkeys $ \fk -> _fkTable fk == refqt && _fkRefTable fk == qt - let deps = [ SchemaDependency (SOTableObj refqt $ TOCons consName) "remote_fkey" - , SchemaDependency (SOTableObj refqt $ TOCol refCol) "using_col" + let deps = [ SchemaDependency (SOTableObj refqt $ TOCons consName) DRRemoteFkey + , SchemaDependency (SOTableObj refqt $ TOCol 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 (SOTable refqt) "remote_table" + , SchemaDependency (SOTable refqt) DRRemoteTable ] mapping = HM.toList colMap return (RelInfo rn ArrRel (map swap mapping) refqt False, deps) diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs index 1adf9d1ba2530..1807770c6d05a 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Function.hs @@ -85,7 +85,7 @@ mkFunctionInfo qf rawFuncInfo = do validateFuncArgs funcArgs let funcArgsSeq = Seq.fromList funcArgs - dep = SchemaDependency (SOTable retTable) "table" + dep = SchemaDependency (SOTable retTable) DRTable retTable = QualifiedObject retSn (TableName retN) return $ FunctionInfo qf False funTy funcArgsSeq retTable [dep] where diff --git a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs index 942450560a85f..ed60b710e0935 100644 --- a/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs +++ b/server/src-lib/Hasura/RQL/DDL/Schema/Table.hs @@ -192,7 +192,7 @@ processTableChanges ti tableDiff = do | oColTy /= nColTy -> do let colId = SOTableObj tn $ TOCol oColName - typeDepObjs = getDependentObjsWith (== "on_type") sc colId + typeDepObjs = getDependentObjsWith (== DROnType) sc colId -- Raise exception if any objects found which are dependant on column type unless (null typeDepObjs) $ throw400 DependencyError $ @@ -206,7 +206,8 @@ processTableChanges ti tableDiff = do -- If any dependant permissions found with the column whose type -- being altered is provided with a session variable, -- then rebuild permission info and update the cache - let sessVarDepObjs = getDependentObjsWith (== "sess_var") sc colId + let sessVarDepObjs = + getDependentObjsWith (== DRSessionVariable) sc colId forM_ sessVarDepObjs $ \objId -> case objId of SOTableObj qt (TOPerm rn pt) -> rebuildPermInfo qt rn pt diff --git a/server/src-lib/Hasura/RQL/GBoolExp.hs b/server/src-lib/Hasura/RQL/GBoolExp.hs index b261e9619c562..c2c771f5a704c 100644 --- a/server/src-lib/Hasura/RQL/GBoolExp.hs +++ b/server/src-lib/Hasura/RQL/GBoolExp.hs @@ -481,15 +481,15 @@ getColExpDeps getColExpDeps tn = \case AVCol colInfo opExps -> let cn = pgiName colInfo - colDepReason = bool "sess_var" "on_type" $ any hasStaticExp opExps + colDepReason = bool DRSessionVariable DROnType $ any hasStaticExp opExps colDep = mkColDep colDepReason tn cn depColsInOpExp = mapMaybe opExpDepCol opExps - colDepsInOpExp = map (mkColDep "on_type" tn) depColsInOpExp + colDepsInOpExp = map (mkColDep DROnType tn) depColsInOpExp in colDep:colDepsInOpExp AVRel relInfo relBoolExp -> let rn = riName relInfo relTN = riRTable relInfo - pd = SchemaDependency (SOTableObj tn (TORel rn)) "on_type" + pd = SchemaDependency (SOTableObj tn (TORel rn)) DROnType in pd : getBoolExpDeps relTN relBoolExp getBoolExpDeps :: QualifiedTable -> AnnBoolExpPartialSQL -> [SchemaDependency] diff --git a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs index d9ac834b9d8ac..e78f88cfc2540 100644 --- a/server/src-lib/Hasura/RQL/Types/SchemaCache.hs +++ b/server/src-lib/Hasura/RQL/Types/SchemaCache.hs @@ -82,6 +82,7 @@ module Hasura.RQL.Types.SchemaCache , SchemaObjId(..) , reportSchemaObj , reportSchemaObjs + , DependencyReason(..) , SchemaDependency(..) , mkParentDep , mkColDep @@ -130,9 +131,9 @@ reportSchemaObjs :: [SchemaObjId] -> T.Text reportSchemaObjs = T.intercalate ", " . map reportSchemaObj mkParentDep :: QualifiedTable -> SchemaDependency -mkParentDep tn = SchemaDependency (SOTable tn) "table" +mkParentDep tn = SchemaDependency (SOTable tn) DRTable -mkColDep :: T.Text -> QualifiedTable -> PGCol -> SchemaDependency +mkColDep :: DependencyReason -> QualifiedTable -> PGCol -> SchemaDependency mkColDep reason tn col = flip SchemaDependency reason . SOTableObj tn $ TOCol col @@ -791,7 +792,7 @@ getDependentObjs :: SchemaCache -> SchemaObjId -> [SchemaObjId] getDependentObjs = getDependentObjsWith (const True) getDependentObjsWith - :: (T.Text -> Bool) -> SchemaCache -> SchemaObjId -> [SchemaObjId] + :: (DependencyReason -> Bool) -> SchemaCache -> SchemaObjId -> [SchemaObjId] getDependentObjsWith f sc objId = -- [ sdObjId sd | sd <- filter (f . sdReason) allDeps] map fst $ filter (isDependency . snd) $ M.toList $ scDepMap sc diff --git a/server/src-lib/Hasura/RQL/Types/SchemaCacheTypes.hs b/server/src-lib/Hasura/RQL/Types/SchemaCacheTypes.hs index 7afc86e42a332..a85c056e0241d 100644 --- a/server/src-lib/Hasura/RQL/Types/SchemaCacheTypes.hs +++ b/server/src-lib/Hasura/RQL/Types/SchemaCacheTypes.hs @@ -55,10 +55,47 @@ instance ToJSON SchemaObjId where instance ToJSONKey SchemaObjId where toJSONKey = toJSONKeyText reportSchemaObj +data DependencyReason + = DRTable + | DRColumn + | DRRemoteTable + | DRLeftColumn + | DRRightColumn + | DRUsingColumn + | DRFkey + | DRRemoteFkey + | DRUntyped + | DROnType + | DRSessionVariable + | DRPayload + | DRParent + deriving (Show, Eq, Generic) + +instance Hashable DependencyReason + +reasonToTxt :: DependencyReason -> Text +reasonToTxt = \case + DRTable -> "table" + DRColumn -> "column" + DRRemoteTable -> "remote_table" + DRLeftColumn -> "left_column" + DRRightColumn -> "right_column" + DRUsingColumn -> "using_column" + DRFkey -> "fkey" + DRRemoteFkey -> "remote_fkey" + DRUntyped -> "untyped" + DROnType -> "on_type" + DRSessionVariable -> "session_variable" + DRPayload -> "payload" + DRParent -> "parent" + +instance ToJSON DependencyReason where + toJSON = String . reasonToTxt + data SchemaDependency = SchemaDependency { sdObjId :: !SchemaObjId - , sdReason :: !T.Text + , sdReason :: !DependencyReason } deriving (Show, Eq, Generic) $(deriveToJSON (aesonDrop 2 snakeCase) ''SchemaDependency) From f974433c09f05fb2f548788b620d0e287e631299 Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Wed, 14 Aug 2019 09:40:25 +0530 Subject: [PATCH 4/5] set jwt expiry test's expiry time to 4 seconds --- server/tests-py/test_jwt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/tests-py/test_jwt.py b/server/tests-py/test_jwt.py index 2a95087c7d4dd..26980f9170c30 100644 --- a/server/tests-py/test_jwt.py +++ b/server/tests-py/test_jwt.py @@ -284,7 +284,7 @@ def test_jwt_expiry(self, hge_ctx, ws_client): 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': ['user'], }) - exp = curr_time + timedelta(seconds=5) + exp = curr_time + timedelta(seconds=4) self.claims['exp'] = round(exp.timestamp()) token = jwt.encode(self.claims, hge_ctx.hge_jwt_key, algorithm='RS512').decode('utf-8') payload = { From 9c39e9b7e307b77558796e047bdee816429cd4ad Mon Sep 17 00:00:00 2001 From: rakeshkky <12475069+rakeshkky@users.noreply.github.com> Date: Wed, 14 Aug 2019 10:12:37 +0530 Subject: [PATCH 5/5] derive Data instance for necessary types to simplify 'hasStaticExp' --- server/graphql-engine.cabal | 1 + server/src-lib/Hasura/Prelude.hs | 1 + server/src-lib/Hasura/RQL/GBoolExp.hs | 41 ++------------- server/src-lib/Hasura/RQL/Types/BoolExp.hs | 8 +-- server/src-lib/Hasura/SQL/DML.hs | 60 +++++++++++----------- server/src-lib/Hasura/SQL/Types.hs | 16 +++--- 6 files changed, 47 insertions(+), 80 deletions(-) diff --git a/server/graphql-engine.cabal b/server/graphql-engine.cabal index c9c8a84952cb3..05ac8233d9e4f 100644 --- a/server/graphql-engine.cabal +++ b/server/graphql-engine.cabal @@ -299,6 +299,7 @@ library QuasiQuotes TypeFamilies NoImplicitPrelude + DeriveDataTypeable if flag(profile) diff --git a/server/src-lib/Hasura/Prelude.hs b/server/src-lib/Hasura/Prelude.hs index db37186dc81ad..f724ab3a758d2 100644 --- a/server/src-lib/Hasura/Prelude.hs +++ b/server/src-lib/Hasura/Prelude.hs @@ -16,6 +16,7 @@ import Control.Monad.Identity as M import Control.Monad.Reader as M import Control.Monad.State.Strict as M import Data.Bool as M (bool) +import Data.Data as M (Data (..)) import Data.Either as M (lefts, partitionEithers, rights) import Data.Foldable as M (foldrM, toList) diff --git a/server/src-lib/Hasura/RQL/GBoolExp.hs b/server/src-lib/Hasura/RQL/GBoolExp.hs index c2c771f5a704c..fcfe725a4e809 100644 --- a/server/src-lib/Hasura/RQL/GBoolExp.hs +++ b/server/src-lib/Hasura/RQL/GBoolExp.hs @@ -13,7 +13,9 @@ import Hasura.SQL.Value import qualified Hasura.SQL.DML as S +import Control.Lens (filtered, has) import Data.Aeson +import Data.Data.Lens (template) import qualified Data.HashMap.Strict as M import qualified Data.Text.Extended as T @@ -437,44 +439,7 @@ mkColCompExp qual lhsCol = mkCompExp (mkQCol lhsCol) pgTypeToAnnType = S.TypeAnn . T.pack . show hasStaticExp :: OpExpG PartialSQLExp -> Bool -hasStaticExp = \case - ACast casts -> any hasStaticExp $ concat $ M.elems casts - - AEQ _ val -> isStaticValue val - ANE _ val -> isStaticValue val - - AIN val -> isStaticValue val - ANIN val -> isStaticValue val - AGT val -> isStaticValue val - ALT val -> isStaticValue val - AGTE val -> isStaticValue val - ALTE val -> isStaticValue val - - ALIKE val -> isStaticValue val - ANLIKE val -> isStaticValue val - AILIKE val -> isStaticValue val - ANILIKE val -> isStaticValue val - - ASIMILAR val -> isStaticValue val - ANSIMILAR val -> isStaticValue val - - AContains val -> isStaticValue val - AContainedIn val -> isStaticValue val - AHasKey val -> isStaticValue val - AHasKeysAny val -> isStaticValue val - AHasKeysAll val -> isStaticValue val - - ASTContains val -> isStaticValue val - ASTCrosses val -> isStaticValue val - ASTEquals val -> isStaticValue val - ASTIntersects val -> isStaticValue val - ASTOverlaps val -> isStaticValue val - ASTTouches val -> isStaticValue val - ASTWithin val -> isStaticValue val - ASTDWithinGeom (DWithinGeomOp r val) -> any isStaticValue [r, val] - ASTDWithinGeog (DWithinGeogOp r val sph) -> any isStaticValue [r, val, sph] - - _ -> False +hasStaticExp = has (template . filtered isStaticValue) getColExpDeps :: QualifiedTable -> AnnBoolExpFldPartialSQL -> [SchemaDependency] diff --git a/server/src-lib/Hasura/RQL/Types/BoolExp.hs b/server/src-lib/Hasura/RQL/Types/BoolExp.hs index d13d139f9afa8..8cd06711a2b3e 100644 --- a/server/src-lib/Hasura/RQL/Types/BoolExp.hs +++ b/server/src-lib/Hasura/RQL/Types/BoolExp.hs @@ -110,7 +110,7 @@ data DWithinGeomOp a = DWithinGeomOp { dwgeomDistance :: !a , dwgeomFrom :: !a - } deriving (Show, Eq, Functor, Foldable, Traversable) + } deriving (Show, Eq, Functor, Foldable, Traversable, Data) $(deriveJSON (aesonDrop 6 snakeCase) ''DWithinGeomOp) data DWithinGeogOp a = @@ -118,7 +118,7 @@ data DWithinGeogOp a = { dwgeogDistance :: !a , dwgeogFrom :: !a , dwgeogUseSpheroid :: !a - } deriving (Show, Eq, Functor, Foldable, Traversable) + } deriving (Show, Eq, Functor, Foldable, Traversable, Data) $(deriveJSON (aesonDrop 6 snakeCase) ''DWithinGeogOp) type CastExp a = M.HashMap PGColType [OpExpG a] @@ -171,7 +171,7 @@ data OpExpG a | CLT !PGCol | CGTE !PGCol | CLTE !PGCol - deriving (Eq, Show, Functor, Foldable, Traversable) + deriving (Eq, Show, Functor, Foldable, Traversable, Data) opExpDepCol :: OpExpG a -> Maybe PGCol opExpDepCol = \case @@ -282,7 +282,7 @@ type PreSetCols = M.HashMap PGCol S.SQLExp data PartialSQLExp = PSESessVar !PgType !SessVar | PSESQLExp !S.SQLExp - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToJSON PartialSQLExp where toJSON = \case diff --git a/server/src-lib/Hasura/SQL/DML.hs b/server/src-lib/Hasura/SQL/DML.hs index 53b847a4ac85c..f7db300e9cfa6 100644 --- a/server/src-lib/Hasura/SQL/DML.hs +++ b/server/src-lib/Hasura/SQL/DML.hs @@ -31,7 +31,7 @@ data Select , selOrderBy :: !(Maybe OrderByExp) , selLimit :: !(Maybe LimitExp) , selOffset :: !(Maybe OffsetExp) - } deriving (Show, Eq) + } deriving (Show, Eq, Data) mkSelect :: Select mkSelect = Select Nothing [] Nothing @@ -40,7 +40,7 @@ mkSelect = Select Nothing [] Nothing newtype LimitExp = LimitExp SQLExp - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL LimitExp where toSQL (LimitExp se) = @@ -48,7 +48,7 @@ instance ToSQL LimitExp where newtype OffsetExp = OffsetExp SQLExp - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL OffsetExp where toSQL (OffsetExp se) = @@ -56,14 +56,14 @@ instance ToSQL OffsetExp where newtype OrderByExp = OrderByExp [OrderByItem] - deriving (Show, Eq) + deriving (Show, Eq, Data) data OrderByItem = OrderByItem { oColumn :: !SQLExp , oType :: !(Maybe OrderType) , oNulls :: !(Maybe NullsOrder) - } deriving (Show, Eq) + } deriving (Show, Eq, Data) instance ToSQL OrderByItem where toSQL (OrderByItem e ot no) = @@ -71,7 +71,7 @@ instance ToSQL OrderByItem where data OrderType = OTAsc | OTDesc - deriving (Show, Eq, Lift) + deriving (Show, Eq, Lift, Data) instance ToSQL OrderType where toSQL OTAsc = "ASC" @@ -80,7 +80,7 @@ instance ToSQL OrderType where data NullsOrder = NFirst | NLast - deriving (Show, Eq, Lift) + deriving (Show, Eq, Lift, Data) instance ToSQL NullsOrder where toSQL NFirst = "NULLS FIRST" @@ -92,7 +92,7 @@ instance ToSQL OrderByExp where newtype GroupByExp = GroupByExp [SQLExp] - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL GroupByExp where toSQL (GroupByExp idens) = @@ -100,7 +100,7 @@ instance ToSQL GroupByExp where newtype FromExp = FromExp [FromItem] - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL FromExp where toSQL (FromExp items) = @@ -141,7 +141,7 @@ mkRowExp extrs = let newtype HavingExp = HavingExp BoolExp - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL HavingExp where toSQL (HavingExp be) = @@ -149,7 +149,7 @@ instance ToSQL HavingExp where newtype WhereFrag = WhereFrag { getWFBoolExp :: BoolExp } - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL WhereFrag where toSQL (WhereFrag be) = @@ -178,7 +178,7 @@ data Qual = QualIden !Iden | QualTable !QualifiedTable | QualVar !T.Text - deriving (Show, Eq) + deriving (Show, Eq, Data) mkQual :: QualifiedTable -> Qual mkQual = QualTable @@ -193,7 +193,7 @@ mkQIden q t = QIden (QualIden (toIden q)) (toIden t) data QIden = QIden !Qual !Iden - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL QIden where toSQL (QIden qual iden) = @@ -201,7 +201,7 @@ instance ToSQL QIden where newtype SQLOp = SQLOp {sqlOpTxt :: T.Text} - deriving (Show, Eq) + deriving (Show, Eq, Data) incOp :: SQLOp incOp = SQLOp "+" @@ -223,7 +223,7 @@ jsonbDeleteAtPathOp = SQLOp "#-" newtype TypeAnn = TypeAnn {unTypeAnn :: T.Text} - deriving (Show, Eq) + deriving (Show, Eq, Data) mkTypeAnn :: PgType -> TypeAnn mkTypeAnn = TypeAnn . T.pack . show @@ -247,7 +247,7 @@ data CountType = CTStar | CTSimple ![PGCol] | CTDistinct ![PGCol] - deriving(Show, Eq) + deriving(Show, Eq, Data) instance ToSQL CountType where toSQL CTStar = "*" @@ -258,7 +258,7 @@ instance ToSQL CountType where newtype TupleExp = TupleExp [SQLExp] - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL TupleExp where toSQL (TupleExp exps) = @@ -283,7 +283,7 @@ data SQLExp | SEArray ![SQLExp] | SETuple !TupleExp | SECount !CountType - deriving (Show, Eq) + deriving (Show, Eq, Data) withTyAnn :: PGColType -> SQLExp -> SQLExp withTyAnn colTy v = SETyAnn v $ TypeAnn $ T.pack $ show colTy @@ -293,7 +293,7 @@ instance J.ToJSON SQLExp where newtype Alias = Alias { getAlias :: Iden } - deriving (Show, Eq, Hashable) + deriving (Show, Eq, Hashable, Data) instance IsIden Alias where toIden (Alias iden) = iden @@ -349,7 +349,7 @@ intToSQLExp = SEUnsafe . T.pack . show data Extractor = Extractor !SQLExp !(Maybe Alias) - deriving (Show, Eq) + deriving (Show, Eq, Data) mkSQLOpExp :: SQLOp @@ -394,7 +394,7 @@ instance ToSQL Extractor where data DistinctExpr = DistinctSimple | DistinctOn ![SQLExp] - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL DistinctExpr where toSQL DistinctSimple = "DISTINCT" @@ -409,7 +409,7 @@ data FromItem | FISelect !Lateral !Select !Alias | FIValues !ValuesExp !Alias !(Maybe [PGCol]) | FIJoin !JoinExpr - deriving (Show, Eq) + deriving (Show, Eq, Data) mkSelFromItem :: Select -> Alias -> FromItem mkSelFromItem = FISelect (Lateral False) @@ -440,7 +440,7 @@ instance ToSQL FromItem where toSQL je newtype Lateral = Lateral Bool - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL Lateral where toSQL (Lateral True) = "LATERAL" @@ -452,7 +452,7 @@ data JoinExpr , tjeType :: !JoinType , tjeRight :: !FromItem , tjeJC :: !JoinCond - } deriving (Show, Eq) + } deriving (Show, Eq, Data) instance ToSQL JoinExpr where toSQL je = @@ -466,7 +466,7 @@ data JoinType | LeftOuter | RightOuter | FullOuter - deriving (Eq, Show) + deriving (Eq, Show, Data) instance ToSQL JoinType where toSQL Inner = "INNER JOIN" @@ -477,7 +477,7 @@ instance ToSQL JoinType where data JoinCond = JoinOn !BoolExp | JoinUsing ![PGCol] - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL JoinCond where toSQL (JoinOn be) = @@ -498,7 +498,7 @@ data BoolExp | BEExists !Select | BEIN !SQLExp ![SQLExp] | BEExp !SQLExp - deriving (Show, Eq) + deriving (Show, Eq, Data) -- removes extraneous 'AND true's simplifyBoolExp :: BoolExp -> BoolExp @@ -552,7 +552,7 @@ instance ToSQL BoolExp where data BinOp = AndOp | OrOp - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL BinOp where toSQL AndOp = "AND" @@ -578,7 +578,7 @@ data CompareOp | SHasKey | SHasKeysAny | SHasKeysAll - deriving (Eq) + deriving (Eq, Data) instance Show CompareOp where show = \case @@ -722,7 +722,7 @@ instance ToSQL SQLConflict where newtype ValuesExp = ValuesExp [TupleExp] - deriving (Show, Eq) + deriving (Show, Eq, Data) instance ToSQL ValuesExp where toSQL (ValuesExp tuples) = diff --git a/server/src-lib/Hasura/SQL/Types.hs b/server/src-lib/Hasura/SQL/Types.hs index 77121a73a4d7a..c8c35f7e91575 100644 --- a/server/src-lib/Hasura/SQL/Types.hs +++ b/server/src-lib/Hasura/SQL/Types.hs @@ -35,7 +35,7 @@ infixr 6 <+> newtype Iden = Iden { getIdenTxt :: T.Text } - deriving (Show, Eq, FromJSON, ToJSON, Hashable, Semigroup) + deriving (Show, Eq, FromJSON, ToJSON, Hashable, Semigroup, Data) instance ToSQL Iden where toSQL (Iden t) = @@ -90,7 +90,7 @@ class ToTxt a where newtype TableName = TableName { getTableTxt :: T.Text } - deriving (Show, Eq, FromJSON, ToJSON, Hashable, Q.ToPrepArg, Q.FromCol, Lift) + deriving (Show, Eq, FromJSON, ToJSON, Hashable, Q.ToPrepArg, Q.FromCol, Lift, Data) instance IsIden TableName where toIden (TableName t) = Iden t @@ -144,7 +144,7 @@ instance ToSQL ConstraintName where newtype FunctionName = FunctionName { getFunctionTxt :: T.Text } - deriving (Show, Eq, Ord, FromJSON, ToJSON, Q.ToPrepArg, Q.FromCol, Hashable, Lift) + deriving (Show, Eq, Ord, FromJSON, ToJSON, Q.ToPrepArg, Q.FromCol, Hashable, Lift, Data) instance IsIden FunctionName where toIden (FunctionName t) = Iden t @@ -160,7 +160,7 @@ instance ToTxt FunctionName where newtype SchemaName = SchemaName { getSchemaTxt :: T.Text } - deriving (Show, Eq, Ord, FromJSON, ToJSON, Hashable, Q.ToPrepArg, Q.FromCol, Lift) + deriving (Show, Eq, Ord, FromJSON, ToJSON, Hashable, Q.ToPrepArg, Q.FromCol, Lift, Data) publicSchema :: SchemaName publicSchema = SchemaName "public" @@ -178,7 +178,7 @@ data QualifiedObject a = QualifiedObject { qSchema :: !SchemaName , qName :: !a - } deriving (Show, Eq, Functor, Ord, Generic, Lift) + } deriving (Show, Eq, Functor, Ord, Generic, Lift, Data) instance (FromJSON a) => FromJSON (QualifiedObject a) where parseJSON v@(String _) = @@ -229,7 +229,7 @@ type QualifiedFunction = QualifiedObject FunctionName newtype PGCol = PGCol { getPGColTxt :: T.Text } - deriving (Show, Eq, Ord, FromJSON, ToJSON, Hashable, Q.ToPrepArg, Q.FromCol, ToJSONKey, FromJSONKey, Lift) + deriving (Show, Eq, Ord, FromJSON, ToJSON, Hashable, Q.ToPrepArg, Q.FromCol, ToJSONKey, FromJSONKey, Lift, Data) instance IsIden PGCol where toIden (PGCol t) = Iden t @@ -265,7 +265,7 @@ data PGColType | PGGeometry | PGGeography | PGUnknown !T.Text - deriving (Eq, Lift, Generic) + deriving (Eq, Lift, Generic, Data) instance Hashable PGColType @@ -388,7 +388,7 @@ pgTypeOid (PGUnknown _) = PTI.auto data PgType = PgTypeSimple !PGColType | PgTypeArray !PGColType - deriving (Eq) + deriving (Eq, Data) instance Show PgType where show = \case