{-# LANGUAGE TemplateHaskellQuotes #-}

-- | Helper functions for generating the schema of database tables
module Hasura.GraphQL.Schema.Table
  ( getTableGQLName,
    tableSelectColumnsEnum,
    tableSelectColumnsPredEnum,
    tableUpdateColumnsEnum,
    updateColumnsPlaceholderParser,
    tableSelectPermissions,
    tableSelectFields,
    tableColumns,
    tableSelectColumns,
    tableSelectComputedFields,
    tableUpdateColumns,
    getTableIdentifierName,
  )
where

import Control.Lens ((^?), _1)
import Data.Has
import Data.HashMap.Strict qualified as HashMap
import Data.HashSet qualified as Set
import Data.Text.Casing (GQLNameIdentifier)
import Data.Text.Casing qualified as C
import Data.Text.Extended
import Hasura.Base.Error (QErr)
import Hasura.GraphQL.Schema.Backend
import Hasura.GraphQL.Schema.Common
import Hasura.GraphQL.Schema.Parser (Kind (..), Parser)
import Hasura.GraphQL.Schema.Parser qualified as P
import Hasura.GraphQL.Schema.Typename
import Hasura.Name qualified as Name
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp (AnnRedactionExpPartialSQL, AnnRedactionExpUnpreparedValue)
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.Roles (RoleName)
import Hasura.RQL.Types.SchemaCache hiding (askTableInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.Table.Cache
import Language.GraphQL.Draft.Syntax qualified as G

-- | Helper function to get the table GraphQL name. A table may have a
-- custom name configured with it. When the custom name exists, the GraphQL nodes
-- that are generated according to the custom name. For example: Let's say,
-- we have a table called `users address`, the name of the table is not GraphQL
-- compliant so we configure the table with a GraphQL compliant name,
-- say `users_address`
-- The generated top-level nodes of this table will be like `users_address`,
-- `insert_users_address` etc
getTableGQLName ::
  forall b m.
  (Backend b, MonadError QErr m) =>
  TableInfo b ->
  m G.Name
getTableGQLName :: forall (b :: BackendType) (m :: * -> *).
(Backend b, MonadError QErr m) =>
TableInfo b -> m Name
getTableGQLName TableInfo b
tableInfo = do
  let coreInfo :: TableCoreInfo b
coreInfo = TableInfo b -> TableCoreInfo b
forall (b :: BackendType). TableInfo b -> TableCoreInfo b
_tiCoreInfo TableInfo b
tableInfo
      tableName :: TableName b
tableName = TableCoreInfo b -> TableName b
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> TableName b
_tciName TableCoreInfo b
coreInfo
      tableCustomName :: Maybe Name
tableCustomName = TableConfig b -> Maybe Name
forall (b :: BackendType). TableConfig b -> Maybe Name
_tcCustomName (TableConfig b -> Maybe Name) -> TableConfig b -> Maybe Name
forall a b. (a -> b) -> a -> b
$ TableCoreInfo b -> TableConfig b
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> TableConfig b
_tciCustomConfig TableCoreInfo b
coreInfo
  Maybe Name
tableCustomName
    Maybe Name -> Either QErr Name -> Either QErr Name
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
`onNothing` forall (b :: BackendType).
Backend b =>
TableName b -> Either QErr Name
tableGraphQLName @b TableName b
tableName
    Either QErr Name -> (QErr -> m Name) -> m Name
forall (m :: * -> *) e a.
Applicative m =>
Either e a -> (e -> m a) -> m a
`onLeft` QErr -> m Name
forall a. QErr -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError

-- | similar to @getTableGQLName@ but returns table name as a list with name pieces
--   instead of concatenating schema and table name together.
getTableIdentifierName ::
  forall b m.
  (Backend b, MonadError QErr m) =>
  TableInfo b ->
  m (C.GQLNameIdentifier)
getTableIdentifierName :: forall (b :: BackendType) (m :: * -> *).
(Backend b, MonadError QErr m) =>
TableInfo b -> m GQLNameIdentifier
getTableIdentifierName TableInfo b
tableInfo =
  let coreInfo :: TableCoreInfo b
coreInfo = TableInfo b -> TableCoreInfo b
forall (b :: BackendType). TableInfo b -> TableCoreInfo b
_tiCoreInfo TableInfo b
tableInfo
      tableName :: TableName b
tableName = TableCoreInfo b -> TableName b
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> TableName b
_tciName TableCoreInfo b
coreInfo
      tableCustomName :: Maybe GQLNameIdentifier
tableCustomName = (Name -> GQLNameIdentifier)
-> Maybe Name -> Maybe GQLNameIdentifier
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Name -> GQLNameIdentifier
C.fromCustomName (Maybe Name -> Maybe GQLNameIdentifier)
-> Maybe Name -> Maybe GQLNameIdentifier
forall a b. (a -> b) -> a -> b
$ TableConfig b -> Maybe Name
forall (b :: BackendType). TableConfig b -> Maybe Name
_tcCustomName (TableConfig b -> Maybe Name) -> TableConfig b -> Maybe Name
forall a b. (a -> b) -> a -> b
$ TableCoreInfo b -> TableConfig b
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> TableConfig b
_tciCustomConfig TableCoreInfo b
coreInfo
   in Maybe GQLNameIdentifier
-> m GQLNameIdentifier -> m GQLNameIdentifier
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing
        Maybe GQLNameIdentifier
tableCustomName
        (Either QErr GQLNameIdentifier -> m GQLNameIdentifier
forall e (m :: * -> *) a. MonadError e m => Either e a -> m a
liftEither (Either QErr GQLNameIdentifier -> m GQLNameIdentifier)
-> Either QErr GQLNameIdentifier -> m GQLNameIdentifier
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
Backend b =>
TableName b -> Either QErr GQLNameIdentifier
getTableIdentifier @b TableName b
tableName)

-- | Table select columns enum
--
-- Parser for an enum type that matches the columns of the given
-- table. Used as a parameter for "distinct", among others. Maps to
-- the table_select_column object.
--
-- Return Nothing if there's no column the current user has "select"
-- permissions for.
tableSelectColumnsEnum ::
  forall b r m n.
  (MonadBuildSchema b r m n) =>
  TableInfo b ->
  SchemaT r m (Maybe (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)))
tableSelectColumnsEnum :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *).
MonadBuildSchema b r m n =>
TableInfo b
-> SchemaT
     r
     m
     (Maybe
        (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)))
tableSelectColumnsEnum TableInfo b
tableInfo = do
  ResolvedSourceCustomization
customization <- (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve ((SourceInfo b -> ResolvedSourceCustomization)
 -> SchemaT r m ResolvedSourceCustomization)
-> (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
SourceInfo b -> ResolvedSourceCustomization
_siCustomization @b
  let tCase :: NamingCase
tCase = ResolvedSourceCustomization -> NamingCase
_rscNamingConvention ResolvedSourceCustomization
customization
      mkTypename :: Name -> Name
mkTypename = MkTypename -> Name -> Name
runMkTypename (MkTypename -> Name -> Name) -> MkTypename -> Name -> Name
forall a b. (a -> b) -> a -> b
$ ResolvedSourceCustomization -> MkTypename
_rscTypeNames ResolvedSourceCustomization
customization
  GQLNameIdentifier
tableGQLName <- forall (b :: BackendType) (m :: * -> *).
(Backend b, MonadError QErr m) =>
TableInfo b -> m GQLNameIdentifier
getTableIdentifierName @b TableInfo b
tableInfo
  [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
columnsWithRedactionExps <- TableInfo b
-> SchemaT
     r m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has SchemaContext r, Has (SourceInfo b) r) =>
TableInfo b
-> m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
tableSelectColumns TableInfo b
tableInfo
  let columns :: [StructuredColumnInfo b]
columns = (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
-> StructuredColumnInfo b
forall a b. (a, b) -> a
fst ((StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
 -> StructuredColumnInfo b)
-> [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
-> [StructuredColumnInfo b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
columnsWithRedactionExps
  let enumName :: Name
enumName = Name -> Name
mkTypename (Name -> Name) -> Name -> Name
forall a b. (a -> b) -> a -> b
$ NamingCase -> GQLNameIdentifier -> Name
applyTypeNameCaseIdentifier NamingCase
tCase (GQLNameIdentifier -> Name) -> GQLNameIdentifier -> Name
forall a b. (a -> b) -> a -> b
$ GQLNameIdentifier -> GQLNameIdentifier
mkTableSelectColumnTypeName GQLNameIdentifier
tableGQLName
      description :: Maybe Description
description =
        Description -> Maybe Description
forall a. a -> Maybe a
Just
          (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description
          (Text -> Description) -> Text -> Description
forall a b. (a -> b) -> a -> b
$ Text
"select columns of table "
          Text -> TableName b -> Text
forall t. ToTxt t => Text -> t -> Text
<>> TableInfo b -> TableName b
forall (b :: BackendType). TableInfo b -> TableName b
tableInfoName TableInfo b
tableInfo
  -- We noticed many 'Definition's allocated, from 'define' below, so memoize
  -- to gain more sharing and lower memory residency.
  let columnDefinitions :: Maybe
  (NonEmpty
     (Definition MetadataObjId EnumValueInfo,
      (Column b, AnnRedactionExpUnpreparedValue b)))
columnDefinitions =
        [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
columnsWithRedactionExps
          [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
-> ((StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
    -> (Definition MetadataObjId EnumValueInfo,
        (Column b, AnnRedactionExpUnpreparedValue b)))
-> [(Definition MetadataObjId EnumValueInfo,
     (Column b, AnnRedactionExpUnpreparedValue b))]
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> ( \(StructuredColumnInfo b
structuredColumnInfo, AnnRedactionExpUnpreparedValue b
redactionExp) ->
                  let definition :: Definition MetadataObjId EnumValueInfo
definition = Name -> Definition MetadataObjId EnumValueInfo
forall {origin}. Name -> Definition origin EnumValueInfo
define (Name -> Definition MetadataObjId EnumValueInfo)
-> Name -> Definition MetadataObjId EnumValueInfo
forall a b. (a -> b) -> a -> b
$ StructuredColumnInfo b -> Name
forall (b :: BackendType). StructuredColumnInfo b -> Name
structuredColumnInfoName StructuredColumnInfo b
structuredColumnInfo
                      column :: Column b
column = StructuredColumnInfo b -> Column b
forall (b :: BackendType). StructuredColumnInfo b -> Column b
structuredColumnInfoColumn StructuredColumnInfo b
structuredColumnInfo
                   in (Definition MetadataObjId EnumValueInfo
definition, (Column b
column, AnnRedactionExpUnpreparedValue b
redactionExp))
              )
          [(Definition MetadataObjId EnumValueInfo,
  (Column b, AnnRedactionExpUnpreparedValue b))]
-> ([(Definition MetadataObjId EnumValueInfo,
      (Column b, AnnRedactionExpUnpreparedValue b))]
    -> Maybe
         (NonEmpty
            (Definition MetadataObjId EnumValueInfo,
             (Column b, AnnRedactionExpUnpreparedValue b))))
-> Maybe
     (NonEmpty
        (Definition MetadataObjId EnumValueInfo,
         (Column b, AnnRedactionExpUnpreparedValue b)))
forall a b. a -> (a -> b) -> b
& [(Definition MetadataObjId EnumValueInfo,
  (Column b, AnnRedactionExpUnpreparedValue b))]
-> Maybe
     (NonEmpty
        (Definition MetadataObjId EnumValueInfo,
         (Column b, AnnRedactionExpUnpreparedValue b)))
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty
  case Maybe
  (NonEmpty
     (Definition MetadataObjId EnumValueInfo,
      (Column b, AnnRedactionExpUnpreparedValue b)))
columnDefinitions of
    Maybe
  (NonEmpty
     (Definition MetadataObjId EnumValueInfo,
      (Column b, AnnRedactionExpUnpreparedValue b)))
Nothing -> Maybe (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
-> SchemaT
     r
     m
     (Maybe
        (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)))
forall a. a -> SchemaT r m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
forall a. Maybe a
Nothing
    Just NonEmpty
  (Definition MetadataObjId EnumValueInfo,
   (Column b, AnnRedactionExpUnpreparedValue b))
columnDefinitions' ->
      Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)
-> Maybe
     (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
forall a. a -> Maybe a
Just
        (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)
 -> Maybe
      (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)))
-> SchemaT
     r m (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
-> SchemaT
     r
     m
     (Maybe
        (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Name
-> (Name, Maybe Description, [StructuredColumnInfo b])
-> SchemaT
     r m (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
-> SchemaT
     r m (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
forall (m :: * -> *) a (p :: (* -> *) -> * -> *) (n :: * -> *) b.
(MonadMemoize m, Ord a, Typeable a, Typeable p, MonadParse n,
 Typeable b) =>
Name -> a -> m (p n b) -> m (p n b)
P.memoizeOn
          'tableSelectColumnsEnum
          (Name
enumName, Maybe Description
description, [StructuredColumnInfo b]
columns)
          (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)
-> SchemaT
     r m (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
forall a. a -> SchemaT r m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)
 -> SchemaT
      r m (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)))
-> Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)
-> SchemaT
     r m (Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b))
forall a b. (a -> b) -> a -> b
$ Name
-> Maybe Description
-> NonEmpty
     (Definition MetadataObjId EnumValueInfo,
      (Column b, AnnRedactionExpUnpreparedValue b))
-> Parser 'Both n (Column b, AnnRedactionExpUnpreparedValue b)
forall (m :: * -> *) origin a.
MonadParse m =>
Name
-> Maybe Description
-> NonEmpty (Definition origin EnumValueInfo, a)
-> Parser origin 'Both m a
P.enum Name
enumName Maybe Description
description NonEmpty
  (Definition MetadataObjId EnumValueInfo,
   (Column b, AnnRedactionExpUnpreparedValue b))
columnDefinitions')
  where
    define :: Name -> Definition origin EnumValueInfo
define Name
name =
      Name
-> Maybe Description
-> Maybe origin
-> [Directive Void]
-> EnumValueInfo
-> Definition origin EnumValueInfo
forall origin a.
Name
-> Maybe Description
-> Maybe origin
-> [Directive Void]
-> a
-> Definition origin a
P.Definition Name
name (Description -> Maybe Description
forall a. a -> Maybe a
Just (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description Text
"column name") Maybe origin
forall a. Maybe a
Nothing [] EnumValueInfo
P.EnumValueInfo

-- | Table select columns enum of a certain type.
--
-- Parser for an enum type that matches, of a given table, certain columns which
-- satisfy a predicate.  Used as a parameter for aggregation predicate
-- arguments, among others. Maps to the table_select_column object.
--
-- Return Nothing if there's no column the current user has "select"
-- permissions for.
tableSelectColumnsPredEnum ::
  forall b r m n.
  (MonadBuildSchema b r m n) =>
  (ColumnType b -> Bool) ->
  GQLNameIdentifier ->
  TableInfo b ->
  SchemaT r m (Maybe (Parser 'Both n (Column b)))
tableSelectColumnsPredEnum :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *).
MonadBuildSchema b r m n =>
(ColumnType b -> Bool)
-> GQLNameIdentifier
-> TableInfo b
-> SchemaT r m (Maybe (Parser 'Both n (Column b)))
tableSelectColumnsPredEnum ColumnType b -> Bool
columnPredicate GQLNameIdentifier
predName TableInfo b
tableInfo = do
  ResolvedSourceCustomization
customization <- (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve ((SourceInfo b -> ResolvedSourceCustomization)
 -> SchemaT r m ResolvedSourceCustomization)
-> (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
SourceInfo b -> ResolvedSourceCustomization
_siCustomization @b
  let tCase :: NamingCase
tCase = ResolvedSourceCustomization -> NamingCase
_rscNamingConvention ResolvedSourceCustomization
customization
      mkTypename :: Name -> Name
mkTypename = MkTypename -> Name -> Name
runMkTypename (MkTypename -> Name -> Name) -> MkTypename -> Name -> Name
forall a b. (a -> b) -> a -> b
$ ResolvedSourceCustomization -> MkTypename
_rscTypeNames ResolvedSourceCustomization
customization
      predName' :: Name
predName' = NamingCase -> GQLNameIdentifier -> Name
applyFieldNameCaseIdentifier NamingCase
tCase GQLNameIdentifier
predName
  GQLNameIdentifier
tableGQLName <- forall (b :: BackendType) (m :: * -> *).
(Backend b, MonadError QErr m) =>
TableInfo b -> m GQLNameIdentifier
getTableIdentifierName @b TableInfo b
tableInfo
  [ColumnInfo b]
columns <- (ColumnInfo b -> Bool) -> [ColumnInfo b] -> [ColumnInfo b]
forall a. (a -> Bool) -> [a] -> [a]
filter (ColumnType b -> Bool
columnPredicate (ColumnType b -> Bool)
-> (ColumnInfo b -> ColumnType b) -> ColumnInfo b -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ColumnInfo b -> ColumnType b
forall (b :: BackendType). ColumnInfo b -> ColumnType b
ciType) ([ColumnInfo b] -> [ColumnInfo b])
-> ([(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
    -> [ColumnInfo b])
-> [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
-> [ColumnInfo b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
 -> Maybe (ColumnInfo b))
-> [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
-> [ColumnInfo b]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe ((StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
-> Getting
     (First (ColumnInfo b))
     (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
     (ColumnInfo b)
-> Maybe (ColumnInfo b)
forall s a. s -> Getting (First a) s a -> Maybe a
^? (StructuredColumnInfo b
 -> Const (First (ColumnInfo b)) (StructuredColumnInfo b))
-> (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
-> Const
     (First (ColumnInfo b))
     (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
forall s t a b. Field1 s t a b => Lens s t a b
Lens
  (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
  (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
  (StructuredColumnInfo b)
  (StructuredColumnInfo b)
_1 ((StructuredColumnInfo b
  -> Const (First (ColumnInfo b)) (StructuredColumnInfo b))
 -> (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
 -> Const
      (First (ColumnInfo b))
      (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b))
-> ((ColumnInfo b -> Const (First (ColumnInfo b)) (ColumnInfo b))
    -> StructuredColumnInfo b
    -> Const (First (ColumnInfo b)) (StructuredColumnInfo b))
-> Getting
     (First (ColumnInfo b))
     (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
     (ColumnInfo b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ColumnInfo b -> Const (First (ColumnInfo b)) (ColumnInfo b))
-> StructuredColumnInfo b
-> Const (First (ColumnInfo b)) (StructuredColumnInfo b)
forall (b :: BackendType) (p :: * -> * -> *) (f :: * -> *).
(Choice p, Applicative f) =>
p (ColumnInfo b) (f (ColumnInfo b))
-> p (StructuredColumnInfo b) (f (StructuredColumnInfo b))
_SCIScalarColumn) ([(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
 -> [ColumnInfo b])
-> SchemaT
     r m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
-> SchemaT r m [ColumnInfo b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TableInfo b
-> SchemaT
     r m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has SchemaContext r, Has (SourceInfo b) r) =>
TableInfo b
-> m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
tableSelectColumns TableInfo b
tableInfo
  let enumName :: Name
enumName = Name -> Name
mkTypename (Name -> Name) -> Name -> Name
forall a b. (a -> b) -> a -> b
$ NamingCase -> GQLNameIdentifier -> Name
applyTypeNameCaseIdentifier NamingCase
tCase (GQLNameIdentifier -> Name) -> GQLNameIdentifier -> Name
forall a b. (a -> b) -> a -> b
$ GQLNameIdentifier -> GQLNameIdentifier -> GQLNameIdentifier
mkSelectColumnPredTypeName GQLNameIdentifier
tableGQLName GQLNameIdentifier
predName
      description :: Maybe Description
description =
        Description -> Maybe Description
forall a. a -> Maybe a
Just
          (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description
          (Text -> Description) -> Text -> Description
forall a b. (a -> b) -> a -> b
$ Text
"select \""
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Name -> Text
G.unName Name
predName'
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\" columns of table "
          Text -> TableName b -> Text
forall t. ToTxt t => Text -> t -> Text
<>> TableInfo b -> TableName b
forall (b :: BackendType). TableInfo b -> TableName b
tableInfoName TableInfo b
tableInfo
  Maybe (Parser 'Both n (Column b))
-> SchemaT r m (Maybe (Parser 'Both n (Column b)))
forall a. a -> SchemaT r m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (Maybe (Parser 'Both n (Column b))
 -> SchemaT r m (Maybe (Parser 'Both n (Column b))))
-> Maybe (Parser 'Both n (Column b))
-> SchemaT r m (Maybe (Parser 'Both n (Column b)))
forall a b. (a -> b) -> a -> b
$ Name
-> Maybe Description
-> NonEmpty (Definition MetadataObjId EnumValueInfo, Column b)
-> Parser 'Both n (Column b)
forall (m :: * -> *) origin a.
MonadParse m =>
Name
-> Maybe Description
-> NonEmpty (Definition origin EnumValueInfo, a)
-> Parser origin 'Both m a
P.enum Name
enumName Maybe Description
description
    (NonEmpty (Definition MetadataObjId EnumValueInfo, Column b)
 -> Parser 'Both n (Column b))
-> Maybe
     (NonEmpty (Definition MetadataObjId EnumValueInfo, Column b))
-> Maybe (Parser 'Both n (Column b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Definition MetadataObjId EnumValueInfo, Column b)]
-> Maybe
     (NonEmpty (Definition MetadataObjId EnumValueInfo, Column b))
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty
      [ ( Name -> Definition MetadataObjId EnumValueInfo
forall {origin}. Name -> Definition origin EnumValueInfo
define (Name -> Definition MetadataObjId EnumValueInfo)
-> Name -> Definition MetadataObjId EnumValueInfo
forall a b. (a -> b) -> a -> b
$ ColumnInfo b -> Name
forall (b :: BackendType). ColumnInfo b -> Name
ciName ColumnInfo b
column,
          ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
column
        )
        | ColumnInfo b
column <- [ColumnInfo b]
columns
      ]
  where
    define :: Name -> Definition origin EnumValueInfo
define Name
name =
      Name
-> Maybe Description
-> Maybe origin
-> [Directive Void]
-> EnumValueInfo
-> Definition origin EnumValueInfo
forall origin a.
Name
-> Maybe Description
-> Maybe origin
-> [Directive Void]
-> a
-> Definition origin a
P.Definition Name
name (Description -> Maybe Description
forall a. a -> Maybe a
Just (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description Text
"column name") Maybe origin
forall a. Maybe a
Nothing [] EnumValueInfo
P.EnumValueInfo

-- | Table update columns enum
--
-- Parser for an enum type that matches the columns of the given
-- table. Used for conflict resolution in "insert" mutations, among
-- others. Maps to the table_update_column object.
tableUpdateColumnsEnum ::
  forall b r m n.
  (MonadBuildSchema b r m n) =>
  TableInfo b ->
  SchemaT r m (Maybe (Parser 'Both n (Column b)))
tableUpdateColumnsEnum :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *).
MonadBuildSchema b r m n =>
TableInfo b -> SchemaT r m (Maybe (Parser 'Both n (Column b)))
tableUpdateColumnsEnum TableInfo b
tableInfo = do
  RoleName
roleName <- (SchemaContext -> RoleName) -> SchemaT r m RoleName
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve SchemaContext -> RoleName
scRole
  ResolvedSourceCustomization
customization <- (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve ((SourceInfo b -> ResolvedSourceCustomization)
 -> SchemaT r m ResolvedSourceCustomization)
-> (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
SourceInfo b -> ResolvedSourceCustomization
_siCustomization @b
  let tCase :: NamingCase
tCase = ResolvedSourceCustomization -> NamingCase
_rscNamingConvention ResolvedSourceCustomization
customization
      mkTypename :: Name -> Name
mkTypename = MkTypename -> Name -> Name
runMkTypename (MkTypename -> Name -> Name) -> MkTypename -> Name -> Name
forall a b. (a -> b) -> a -> b
$ ResolvedSourceCustomization -> MkTypename
_rscTypeNames ResolvedSourceCustomization
customization
  GQLNameIdentifier
tableGQLName <- TableInfo b -> SchemaT r m GQLNameIdentifier
forall (b :: BackendType) (m :: * -> *).
(Backend b, MonadError QErr m) =>
TableInfo b -> m GQLNameIdentifier
getTableIdentifierName TableInfo b
tableInfo
  let enumName :: Name
enumName = Name -> Name
mkTypename (Name -> Name) -> Name -> Name
forall a b. (a -> b) -> a -> b
$ NamingCase -> GQLNameIdentifier -> Name
applyTypeNameCaseIdentifier NamingCase
tCase (GQLNameIdentifier -> Name) -> GQLNameIdentifier -> Name
forall a b. (a -> b) -> a -> b
$ GQLNameIdentifier -> GQLNameIdentifier
mkTableUpdateColumnTypeName GQLNameIdentifier
tableGQLName
      tableName :: TableName b
tableName = TableInfo b -> TableName b
forall (b :: BackendType). TableInfo b -> TableName b
tableInfoName TableInfo b
tableInfo
      enumDesc :: Maybe Description
enumDesc = Description -> Maybe Description
forall a. a -> Maybe a
Just (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description (Text -> Description) -> Text -> Description
forall a b. (a -> b) -> a -> b
$ Text
"update columns of table " Text -> TableName b -> Text
forall t. ToTxt t => Text -> t -> Text
<>> TableName b
tableName
      enumValues :: [(Definition MetadataObjId EnumValueInfo, Column b)]
enumValues = do
        ColumnInfo b
column <- RoleName -> TableInfo b -> [ColumnInfo b]
forall (b :: BackendType).
Backend b =>
RoleName -> TableInfo b -> [ColumnInfo b]
tableUpdateColumns RoleName
roleName TableInfo b
tableInfo
        (Definition MetadataObjId EnumValueInfo, Column b)
-> [(Definition MetadataObjId EnumValueInfo, Column b)]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Name -> Definition MetadataObjId EnumValueInfo
forall {origin}. Name -> Definition origin EnumValueInfo
define (Name -> Definition MetadataObjId EnumValueInfo)
-> Name -> Definition MetadataObjId EnumValueInfo
forall a b. (a -> b) -> a -> b
$ ColumnInfo b -> Name
forall (b :: BackendType). ColumnInfo b -> Name
ciName ColumnInfo b
column, ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
column)
  Maybe (Parser 'Both n (Column b))
-> SchemaT r m (Maybe (Parser 'Both n (Column b)))
forall a. a -> SchemaT r m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (Parser 'Both n (Column b))
 -> SchemaT r m (Maybe (Parser 'Both n (Column b))))
-> Maybe (Parser 'Both n (Column b))
-> SchemaT r m (Maybe (Parser 'Both n (Column b)))
forall a b. (a -> b) -> a -> b
$ Name
-> Maybe Description
-> NonEmpty (Definition MetadataObjId EnumValueInfo, Column b)
-> Parser 'Both n (Column b)
forall (m :: * -> *) origin a.
MonadParse m =>
Name
-> Maybe Description
-> NonEmpty (Definition origin EnumValueInfo, a)
-> Parser origin 'Both m a
P.enum Name
enumName Maybe Description
enumDesc (NonEmpty (Definition MetadataObjId EnumValueInfo, Column b)
 -> Parser 'Both n (Column b))
-> Maybe
     (NonEmpty (Definition MetadataObjId EnumValueInfo, Column b))
-> Maybe (Parser 'Both n (Column b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Definition MetadataObjId EnumValueInfo, Column b)]
-> Maybe
     (NonEmpty (Definition MetadataObjId EnumValueInfo, Column b))
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty [(Definition MetadataObjId EnumValueInfo, Column b)]
enumValues
  where
    define :: Name -> Definition origin EnumValueInfo
define Name
name = Name
-> Maybe Description
-> Maybe origin
-> [Directive Void]
-> EnumValueInfo
-> Definition origin EnumValueInfo
forall origin a.
Name
-> Maybe Description
-> Maybe origin
-> [Directive Void]
-> a
-> Definition origin a
P.Definition Name
name (Description -> Maybe Description
forall a. a -> Maybe a
Just (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description Text
"column name") Maybe origin
forall a. Maybe a
Nothing [] EnumValueInfo
P.EnumValueInfo

-- If there's no column for which the current user has "update"
-- permissions, this functions returns an enum that only contains a
-- placeholder, so as to still allow this type to exist in the schema.
updateColumnsPlaceholderParser ::
  forall b r m n.
  (MonadBuildSchema b r m n) =>
  TableInfo b ->
  SchemaT r m (Parser 'Both n (Maybe (Column b)))
updateColumnsPlaceholderParser :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *).
MonadBuildSchema b r m n =>
TableInfo b -> SchemaT r m (Parser 'Both n (Maybe (Column b)))
updateColumnsPlaceholderParser TableInfo b
tableInfo = do
  ResolvedSourceCustomization
customization <- (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve ((SourceInfo b -> ResolvedSourceCustomization)
 -> SchemaT r m ResolvedSourceCustomization)
-> (SourceInfo b -> ResolvedSourceCustomization)
-> SchemaT r m ResolvedSourceCustomization
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
SourceInfo b -> ResolvedSourceCustomization
_siCustomization @b
  let tCase :: NamingCase
tCase = ResolvedSourceCustomization -> NamingCase
_rscNamingConvention ResolvedSourceCustomization
customization
      mkTypename :: Name -> Name
mkTypename = MkTypename -> Name -> Name
runMkTypename (MkTypename -> Name -> Name) -> MkTypename -> Name -> Name
forall a b. (a -> b) -> a -> b
$ ResolvedSourceCustomization -> MkTypename
_rscTypeNames ResolvedSourceCustomization
customization
  Maybe (Parser MetadataObjId 'Both n (Column b))
maybeEnum <- TableInfo b
-> SchemaT r m (Maybe (Parser MetadataObjId 'Both n (Column b)))
forall (b :: BackendType) r (m :: * -> *) (n :: * -> *).
MonadBuildSchema b r m n =>
TableInfo b -> SchemaT r m (Maybe (Parser 'Both n (Column b)))
tableUpdateColumnsEnum TableInfo b
tableInfo
  case Maybe (Parser MetadataObjId 'Both n (Column b))
maybeEnum of
    Just Parser MetadataObjId 'Both n (Column b)
e -> Parser 'Both n (Maybe (Column b))
-> SchemaT r m (Parser 'Both n (Maybe (Column b)))
forall a. a -> SchemaT r m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Parser 'Both n (Maybe (Column b))
 -> SchemaT r m (Parser 'Both n (Maybe (Column b))))
-> Parser 'Both n (Maybe (Column b))
-> SchemaT r m (Parser 'Both n (Maybe (Column b)))
forall a b. (a -> b) -> a -> b
$ Column b -> Maybe (Column b)
forall a. a -> Maybe a
Just (Column b -> Maybe (Column b))
-> Parser MetadataObjId 'Both n (Column b)
-> Parser 'Both n (Maybe (Column b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser MetadataObjId 'Both n (Column b)
e
    Maybe (Parser MetadataObjId 'Both n (Column b))
Nothing -> do
      GQLNameIdentifier
tableGQLName <- TableInfo b -> SchemaT r m GQLNameIdentifier
forall (b :: BackendType) (m :: * -> *).
(Backend b, MonadError QErr m) =>
TableInfo b -> m GQLNameIdentifier
getTableIdentifierName TableInfo b
tableInfo
      let enumName :: Name
enumName = Name -> Name
mkTypename (Name -> Name) -> Name -> Name
forall a b. (a -> b) -> a -> b
$ NamingCase -> GQLNameIdentifier -> Name
applyTypeNameCaseIdentifier NamingCase
tCase (GQLNameIdentifier -> Name) -> GQLNameIdentifier -> Name
forall a b. (a -> b) -> a -> b
$ GQLNameIdentifier -> GQLNameIdentifier
mkTableUpdateColumnTypeName GQLNameIdentifier
tableGQLName
      Parser 'Both n (Maybe (Column b))
-> SchemaT r m (Parser 'Both n (Maybe (Column b)))
forall a. a -> SchemaT r m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        (Parser 'Both n (Maybe (Column b))
 -> SchemaT r m (Parser 'Both n (Maybe (Column b))))
-> Parser 'Both n (Maybe (Column b))
-> SchemaT r m (Parser 'Both n (Maybe (Column b)))
forall a b. (a -> b) -> a -> b
$ Name
-> Maybe Description
-> NonEmpty
     (Definition MetadataObjId EnumValueInfo, Maybe (Column b))
-> Parser 'Both n (Maybe (Column b))
forall (m :: * -> *) origin a.
MonadParse m =>
Name
-> Maybe Description
-> NonEmpty (Definition origin EnumValueInfo, a)
-> Parser origin 'Both m a
P.enum Name
enumName (Description -> Maybe Description
forall a. a -> Maybe a
Just (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description (Text -> Description) -> Text -> Description
forall a b. (a -> b) -> a -> b
$ Text
"placeholder for update columns of table " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> TableInfo b -> TableName b
forall (b :: BackendType). TableInfo b -> TableName b
tableInfoName TableInfo b
tableInfo TableName b -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" (current role has no relevant permissions)")
        (NonEmpty
   (Definition MetadataObjId EnumValueInfo, Maybe (Column b))
 -> Parser 'Both n (Maybe (Column b)))
-> NonEmpty
     (Definition MetadataObjId EnumValueInfo, Maybe (Column b))
-> Parser 'Both n (Maybe (Column b))
forall a b. (a -> b) -> a -> b
$ (Definition MetadataObjId EnumValueInfo, Maybe (Column b))
-> NonEmpty
     (Definition MetadataObjId EnumValueInfo, Maybe (Column b))
forall a. a -> NonEmpty a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
          ( forall origin a.
Name
-> Maybe Description
-> Maybe origin
-> [Directive Void]
-> a
-> Definition origin a
P.Definition @_ @P.EnumValueInfo Name
Name.__PLACEHOLDER (Description -> Maybe Description
forall a. a -> Maybe a
Just (Description -> Maybe Description)
-> Description -> Maybe Description
forall a b. (a -> b) -> a -> b
$ Text -> Description
G.Description Text
"placeholder (do not use)") Maybe MetadataObjId
forall a. Maybe a
Nothing [] EnumValueInfo
P.EnumValueInfo,
            Maybe (Column b)
forall a. Maybe a
Nothing
          )

tableSelectPermissions :: RoleName -> TableInfo b -> Maybe (SelPermInfo b)
tableSelectPermissions :: forall (b :: BackendType).
RoleName -> TableInfo b -> Maybe (SelPermInfo b)
tableSelectPermissions RoleName
role TableInfo b
tableInfo = RolePermInfo b -> Maybe (SelPermInfo b)
forall (b :: BackendType). RolePermInfo b -> Maybe (SelPermInfo b)
_permSel (RolePermInfo b -> Maybe (SelPermInfo b))
-> RolePermInfo b -> Maybe (SelPermInfo b)
forall a b. (a -> b) -> a -> b
$ RoleName -> TableInfo b -> RolePermInfo b
forall (b :: BackendType).
RoleName -> TableInfo b -> RolePermInfo b
getRolePermInfo RoleName
role TableInfo b
tableInfo

tableSelectFields ::
  forall b r m.
  ( Backend b,
    MonadError QErr m,
    MonadReader r m,
    Has SchemaContext r,
    Has (SourceInfo b) r
  ) =>
  TableInfo b ->
  m [FieldInfo b]
tableSelectFields :: forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has SchemaContext r, Has (SourceInfo b) r) =>
TableInfo b -> m [FieldInfo b]
tableSelectFields TableInfo b
tableInfo = do
  RoleName
roleName <- (SchemaContext -> RoleName) -> m RoleName
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve SchemaContext -> RoleName
scRole
  let tableFields :: FieldInfoMap (FieldInfo b)
tableFields = TableCoreInfoG b (FieldInfo b) (ColumnInfo b)
-> FieldInfoMap (FieldInfo b)
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> FieldInfoMap field
_tciFieldInfoMap (TableCoreInfoG b (FieldInfo b) (ColumnInfo b)
 -> FieldInfoMap (FieldInfo b))
-> (TableInfo b -> TableCoreInfoG b (FieldInfo b) (ColumnInfo b))
-> TableInfo b
-> FieldInfoMap (FieldInfo b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableInfo b -> TableCoreInfoG b (FieldInfo b) (ColumnInfo b)
forall (b :: BackendType). TableInfo b -> TableCoreInfo b
_tiCoreInfo (TableInfo b -> FieldInfoMap (FieldInfo b))
-> TableInfo b -> FieldInfoMap (FieldInfo b)
forall a b. (a -> b) -> a -> b
$ TableInfo b
tableInfo
      permissions :: Maybe (SelPermInfo b)
permissions = RoleName -> TableInfo b -> Maybe (SelPermInfo b)
forall (b :: BackendType).
RoleName -> TableInfo b -> Maybe (SelPermInfo b)
tableSelectPermissions RoleName
roleName TableInfo b
tableInfo
  (FieldInfo b -> m Bool) -> [FieldInfo b] -> m [FieldInfo b]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (RoleName -> Maybe (SelPermInfo b) -> FieldInfo b -> m Bool
canBeSelected RoleName
roleName Maybe (SelPermInfo b)
permissions) ([FieldInfo b] -> m [FieldInfo b])
-> [FieldInfo b] -> m [FieldInfo b]
forall a b. (a -> b) -> a -> b
$ FieldInfoMap (FieldInfo b) -> [FieldInfo b]
forall k v. HashMap k v -> [v]
HashMap.elems FieldInfoMap (FieldInfo b)
tableFields
  where
    canBeSelected :: RoleName -> Maybe (SelPermInfo b) -> FieldInfo b -> m Bool
canBeSelected RoleName
_ Maybe (SelPermInfo b)
Nothing FieldInfo b
_ = Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
    canBeSelected RoleName
_ (Just SelPermInfo b
permissions) (FIColumn (SCIScalarColumn (ColumnInfo b
columnInfo))) =
      Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> m Bool) -> Bool -> m Bool
forall a b. (a -> b) -> a -> b
$! Column b
-> HashMap (Column b) (AnnRedactionExpPartialSQL b) -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HashMap.member (ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
columnInfo) (SelPermInfo b -> HashMap (Column b) (AnnRedactionExpPartialSQL b)
forall (b :: BackendType).
SelPermInfo b -> HashMap (Column b) (AnnRedactionExpPartialSQL b)
spiCols SelPermInfo b
permissions)
    canBeSelected RoleName
_ (Just SelPermInfo b
permissions) (FIColumn (SCIObjectColumn NestedObjectInfo {Bool
Maybe Description
Name
Column b
XNestedObjects b
LogicalModelName
ColumnMutability
_noiSupportsNestedObjects :: XNestedObjects b
_noiColumn :: Column b
_noiName :: Name
_noiType :: LogicalModelName
_noiIsNullable :: Bool
_noiDescription :: Maybe Description
_noiMutability :: ColumnMutability
_noiSupportsNestedObjects :: forall (b :: BackendType). NestedObjectInfo b -> XNestedObjects b
_noiColumn :: forall (b :: BackendType). NestedObjectInfo b -> Column b
_noiName :: forall (b :: BackendType). NestedObjectInfo b -> Name
_noiType :: forall (b :: BackendType). NestedObjectInfo b -> LogicalModelName
_noiIsNullable :: forall (b :: BackendType). NestedObjectInfo b -> Bool
_noiDescription :: forall (b :: BackendType). NestedObjectInfo b -> Maybe Description
_noiMutability :: forall (b :: BackendType). NestedObjectInfo b -> ColumnMutability
..})) =
      Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> m Bool) -> Bool -> m Bool
forall a b. (a -> b) -> a -> b
$! Column b
-> HashMap (Column b) (AnnRedactionExpPartialSQL b) -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HashMap.member Column b
_noiColumn (SelPermInfo b -> HashMap (Column b) (AnnRedactionExpPartialSQL b)
forall (b :: BackendType).
SelPermInfo b -> HashMap (Column b) (AnnRedactionExpPartialSQL b)
spiCols SelPermInfo b
permissions)
    canBeSelected RoleName
role Maybe (SelPermInfo b)
permissions (FIColumn (SCIArrayColumn NestedArrayInfo {Bool
XNestedObjects b
StructuredColumnInfo b
_naiSupportsNestedArrays :: XNestedObjects b
_naiIsNullable :: Bool
_naiColumnInfo :: StructuredColumnInfo b
_naiSupportsNestedArrays :: forall (b :: BackendType). NestedArrayInfo b -> XNestedObjects b
_naiIsNullable :: forall (b :: BackendType). NestedArrayInfo b -> Bool
_naiColumnInfo :: forall (b :: BackendType).
NestedArrayInfo b -> StructuredColumnInfo b
..})) =
      RoleName -> Maybe (SelPermInfo b) -> FieldInfo b -> m Bool
canBeSelected RoleName
role Maybe (SelPermInfo b)
permissions (StructuredColumnInfo b -> FieldInfo b
forall (b :: BackendType). StructuredColumnInfo b -> FieldInfo b
FIColumn StructuredColumnInfo b
_naiColumnInfo)
    canBeSelected RoleName
role Maybe (SelPermInfo b)
_ (FIRelationship RelInfo b
relationshipInfo) = do
      case RelInfo b -> RelTarget b
forall (b :: BackendType). RelInfo b -> RelTarget b
riTarget RelInfo b
relationshipInfo of
        RelTargetNativeQuery NativeQueryName
_ -> [Char] -> m Bool
forall a. HasCallStack => [Char] -> a
error [Char]
"tableSelectFields RelTargetNativeQuery"
        RelTargetTable TableName b
tableName -> do
          TableInfo b
tableInfo' <- TableName b -> m (TableInfo b)
forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has (SourceInfo b) r) =>
TableName b -> m (TableInfo b)
askTableInfo TableName b
tableName
          Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> m Bool) -> Bool -> m Bool
forall a b. (a -> b) -> a -> b
$! Maybe (SelPermInfo b) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (SelPermInfo b) -> Bool) -> Maybe (SelPermInfo b) -> Bool
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
RoleName -> TableInfo b -> Maybe (SelPermInfo b)
tableSelectPermissions @b RoleName
role TableInfo b
tableInfo'
    canBeSelected RoleName
role (Just SelPermInfo b
permissions) (FIComputedField ComputedFieldInfo b
computedFieldInfo) =
      case forall (b :: BackendType).
Backend b =>
ComputedFieldReturn b -> ComputedFieldReturnType b
computedFieldReturnType @b (ComputedFieldInfo b -> ComputedFieldReturn b
forall (b :: BackendType).
ComputedFieldInfo b -> ComputedFieldReturn b
_cfiReturnType ComputedFieldInfo b
computedFieldInfo) of
        ReturnsScalar ScalarType b
_ ->
          Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> m Bool) -> Bool -> m Bool
forall a b. (a -> b) -> a -> b
$! ComputedFieldName
-> HashMap ComputedFieldName (AnnRedactionExpPartialSQL b) -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HashMap.member (ComputedFieldInfo b -> ComputedFieldName
forall (b :: BackendType). ComputedFieldInfo b -> ComputedFieldName
_cfiName ComputedFieldInfo b
computedFieldInfo) (HashMap ComputedFieldName (AnnRedactionExpPartialSQL b) -> Bool)
-> HashMap ComputedFieldName (AnnRedactionExpPartialSQL b) -> Bool
forall a b. (a -> b) -> a -> b
$ SelPermInfo b
-> HashMap ComputedFieldName (AnnRedactionExpPartialSQL b)
forall (b :: BackendType).
SelPermInfo b
-> HashMap ComputedFieldName (AnnRedactionExpPartialSQL b)
spiComputedFields SelPermInfo b
permissions
        ReturnsTable TableName b
tableName -> do
          TableInfo b
tableInfo' <- TableName b -> m (TableInfo b)
forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has (SourceInfo b) r) =>
TableName b -> m (TableInfo b)
askTableInfo TableName b
tableName
          Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> m Bool) -> Bool -> m Bool
forall a b. (a -> b) -> a -> b
$! Maybe (SelPermInfo b) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (SelPermInfo b) -> Bool) -> Maybe (SelPermInfo b) -> Bool
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
RoleName -> TableInfo b -> Maybe (SelPermInfo b)
tableSelectPermissions @b RoleName
role TableInfo b
tableInfo'
        ComputedFieldReturnType b
ReturnsOthers -> Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
    canBeSelected RoleName
_ Maybe (SelPermInfo b)
_ (FIRemoteRelationship RemoteFieldInfo (DBJoinField b)
_) = Bool -> m Bool
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True

tableColumns ::
  forall b. TableInfo b -> [ColumnInfo b]
tableColumns :: forall (b :: BackendType). TableInfo b -> [ColumnInfo b]
tableColumns TableInfo b
tableInfo =
  (ColumnInfo b -> Int) -> [ColumnInfo b] -> [ColumnInfo b]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn ColumnInfo b -> Int
forall (b :: BackendType). ColumnInfo b -> Int
ciPosition ([ColumnInfo b] -> [ColumnInfo b])
-> (TableInfo b -> [ColumnInfo b]) -> TableInfo b -> [ColumnInfo b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FieldInfo b -> Maybe (ColumnInfo b))
-> [FieldInfo b] -> [ColumnInfo b]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe FieldInfo b -> Maybe (ColumnInfo b)
forall {b :: BackendType}. FieldInfo b -> Maybe (ColumnInfo b)
columnInfo ([FieldInfo b] -> [ColumnInfo b])
-> (TableInfo b -> [FieldInfo b]) -> TableInfo b -> [ColumnInfo b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap FieldName (FieldInfo b) -> [FieldInfo b]
forall k v. HashMap k v -> [v]
HashMap.elems (HashMap FieldName (FieldInfo b) -> [FieldInfo b])
-> (TableInfo b -> HashMap FieldName (FieldInfo b))
-> TableInfo b
-> [FieldInfo b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableCoreInfoG b (FieldInfo b) (ColumnInfo b)
-> HashMap FieldName (FieldInfo b)
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> FieldInfoMap field
_tciFieldInfoMap (TableCoreInfoG b (FieldInfo b) (ColumnInfo b)
 -> HashMap FieldName (FieldInfo b))
-> (TableInfo b -> TableCoreInfoG b (FieldInfo b) (ColumnInfo b))
-> TableInfo b
-> HashMap FieldName (FieldInfo b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TableInfo b -> TableCoreInfoG b (FieldInfo b) (ColumnInfo b)
forall (b :: BackendType). TableInfo b -> TableCoreInfo b
_tiCoreInfo (TableInfo b -> [ColumnInfo b]) -> TableInfo b -> [ColumnInfo b]
forall a b. (a -> b) -> a -> b
$ TableInfo b
tableInfo
  where
    columnInfo :: FieldInfo b -> Maybe (ColumnInfo b)
columnInfo (FIColumn (SCIScalarColumn ColumnInfo b
ci)) = ColumnInfo b -> Maybe (ColumnInfo b)
forall a. a -> Maybe a
Just ColumnInfo b
ci
    columnInfo FieldInfo b
_ = Maybe (ColumnInfo b)
forall a. Maybe a
Nothing

-- | Get the columns of a table that may be selected under the given select
-- permissions.
tableSelectColumns ::
  forall b r m.
  ( Backend b,
    MonadError QErr m,
    MonadReader r m,
    Has SchemaContext r,
    Has (SourceInfo b) r
  ) =>
  TableInfo b ->
  m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
tableSelectColumns :: forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has SchemaContext r, Has (SourceInfo b) r) =>
TableInfo b
-> m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
tableSelectColumns TableInfo b
tableInfo = do
  RoleName
roleName <- (SchemaContext -> RoleName) -> m RoleName
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve SchemaContext -> RoleName
scRole
  case SelPermInfo b -> HashMap (Column b) (AnnRedactionExpPartialSQL b)
forall (b :: BackendType).
SelPermInfo b -> HashMap (Column b) (AnnRedactionExpPartialSQL b)
spiCols (SelPermInfo b -> HashMap (Column b) (AnnRedactionExpPartialSQL b))
-> Maybe (SelPermInfo b)
-> Maybe (HashMap (Column b) (AnnRedactionExpPartialSQL b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RoleName -> TableInfo b -> Maybe (SelPermInfo b)
forall (b :: BackendType).
RoleName -> TableInfo b -> Maybe (SelPermInfo b)
tableSelectPermissions RoleName
roleName TableInfo b
tableInfo of
    Maybe (HashMap (Column b) (AnnRedactionExpPartialSQL b))
Nothing -> [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
-> m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
    Just HashMap (Column b) (AnnRedactionExpPartialSQL b)
columnPermissions ->
      (FieldInfo b
 -> Maybe
      (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b))
-> [FieldInfo b]
-> [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe (HashMap (Column b) (AnnRedactionExpPartialSQL b)
-> FieldInfo b
-> Maybe (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
getColumnsAndRedactionExps HashMap (Column b) (AnnRedactionExpPartialSQL b)
columnPermissions) ([FieldInfo b]
 -> [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)])
-> m [FieldInfo b]
-> m [(StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TableInfo b -> m [FieldInfo b]
forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has SchemaContext r, Has (SourceInfo b) r) =>
TableInfo b -> m [FieldInfo b]
tableSelectFields TableInfo b
tableInfo
  where
    getColumnsAndRedactionExps ::
      HashMap (Column b) (AnnRedactionExpPartialSQL b) ->
      FieldInfo b ->
      Maybe ((StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b))
    getColumnsAndRedactionExps :: HashMap (Column b) (AnnRedactionExpPartialSQL b)
-> FieldInfo b
-> Maybe (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
getColumnsAndRedactionExps HashMap (Column b) (AnnRedactionExpPartialSQL b)
columnPermissions = \case
      FIColumn StructuredColumnInfo b
structuredColumnInfo -> do
        AnnRedactionExpPartialSQL b
redactionExp <- Column b
-> HashMap (Column b) (AnnRedactionExpPartialSQL b)
-> Maybe (AnnRedactionExpPartialSQL b)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup (StructuredColumnInfo b -> Column b
forall (b :: BackendType). StructuredColumnInfo b -> Column b
structuredColumnInfoColumn StructuredColumnInfo b
structuredColumnInfo) HashMap (Column b) (AnnRedactionExpPartialSQL b)
columnPermissions
        (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
-> Maybe (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (StructuredColumnInfo b
structuredColumnInfo, PartialSQLExp b -> UnpreparedValue b
forall (b :: BackendType). PartialSQLExp b -> UnpreparedValue b
partialSQLExpToUnpreparedValue (PartialSQLExp b -> UnpreparedValue b)
-> AnnRedactionExpPartialSQL b -> AnnRedactionExpUnpreparedValue b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AnnRedactionExpPartialSQL b
redactionExp)
      FieldInfo b
_ ->
        Maybe (StructuredColumnInfo b, AnnRedactionExpUnpreparedValue b)
forall a. Maybe a
Nothing

-- | Get the computed fields of a table that may be selected under the given
-- select permissions.
tableSelectComputedFields ::
  forall b r m.
  ( Backend b,
    MonadError QErr m,
    MonadReader r m,
    Has SchemaContext r,
    Has (SourceInfo b) r
  ) =>
  TableInfo b ->
  m [ComputedFieldInfo b]
tableSelectComputedFields :: forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has SchemaContext r, Has (SourceInfo b) r) =>
TableInfo b -> m [ComputedFieldInfo b]
tableSelectComputedFields TableInfo b
tableInfo =
  (FieldInfo b -> Maybe (ComputedFieldInfo b))
-> [FieldInfo b] -> [ComputedFieldInfo b]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe FieldInfo b -> Maybe (ComputedFieldInfo b)
forall {b :: BackendType}.
FieldInfo b -> Maybe (ComputedFieldInfo b)
computedFieldInfo ([FieldInfo b] -> [ComputedFieldInfo b])
-> m [FieldInfo b] -> m [ComputedFieldInfo b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TableInfo b -> m [FieldInfo b]
forall (b :: BackendType) r (m :: * -> *).
(Backend b, MonadError QErr m, MonadReader r m,
 Has SchemaContext r, Has (SourceInfo b) r) =>
TableInfo b -> m [FieldInfo b]
tableSelectFields TableInfo b
tableInfo
  where
    computedFieldInfo :: FieldInfo b -> Maybe (ComputedFieldInfo b)
computedFieldInfo (FIComputedField ComputedFieldInfo b
cfi) = ComputedFieldInfo b -> Maybe (ComputedFieldInfo b)
forall a. a -> Maybe a
Just ComputedFieldInfo b
cfi
    computedFieldInfo FieldInfo b
_ = Maybe (ComputedFieldInfo b)
forall a. Maybe a
Nothing

-- | Get the columns of a table that my be updated under the given update
-- permissions.
tableUpdateColumns ::
  forall b.
  (Backend b) =>
  RoleName ->
  TableInfo b ->
  [ColumnInfo b]
tableUpdateColumns :: forall (b :: BackendType).
Backend b =>
RoleName -> TableInfo b -> [ColumnInfo b]
tableUpdateColumns RoleName
role TableInfo b
tableInfo =
  let permissions :: Maybe (UpdPermInfo b)
permissions = RolePermInfo b -> Maybe (UpdPermInfo b)
forall (b :: BackendType). RolePermInfo b -> Maybe (UpdPermInfo b)
_permUpd (RolePermInfo b -> Maybe (UpdPermInfo b))
-> RolePermInfo b -> Maybe (UpdPermInfo b)
forall a b. (a -> b) -> a -> b
$ RoleName -> TableInfo b -> RolePermInfo b
forall (b :: BackendType).
RoleName -> TableInfo b -> RolePermInfo b
getRolePermInfo RoleName
role TableInfo b
tableInfo
   in (ColumnInfo b -> Bool) -> [ColumnInfo b] -> [ColumnInfo b]
forall a. (a -> Bool) -> [a] -> [a]
filter (Maybe (UpdPermInfo b) -> ColumnInfo b -> Bool
isUpdatable Maybe (UpdPermInfo b)
permissions) ([ColumnInfo b] -> [ColumnInfo b])
-> [ColumnInfo b] -> [ColumnInfo b]
forall a b. (a -> b) -> a -> b
$ TableInfo b -> [ColumnInfo b]
forall (b :: BackendType). TableInfo b -> [ColumnInfo b]
tableColumns TableInfo b
tableInfo
  where
    isUpdatable :: Maybe (UpdPermInfo b) -> ColumnInfo b -> Bool
    isUpdatable :: Maybe (UpdPermInfo b) -> ColumnInfo b -> Bool
isUpdatable (Just UpdPermInfo b
permissions) ColumnInfo b
columnInfo = Bool
columnIsUpdatable Bool -> Bool -> Bool
&& Bool
columnIsPermitted Bool -> Bool -> Bool
&& Bool
columnHasNoPreset
      where
        columnIsUpdatable :: Bool
columnIsUpdatable = ColumnMutability -> Bool
_cmIsUpdatable (ColumnInfo b -> ColumnMutability
forall (b :: BackendType). ColumnInfo b -> ColumnMutability
ciMutability ColumnInfo b
columnInfo)
        columnIsPermitted :: Bool
columnIsPermitted = Column b -> HashSet (Column b) -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
Set.member (ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
columnInfo) (UpdPermInfo b -> HashSet (Column b)
forall (b :: BackendType). UpdPermInfo b -> HashSet (Column b)
upiCols UpdPermInfo b
permissions)
        columnHasNoPreset :: Bool
columnHasNoPreset = Bool -> Bool
not (Column b -> HashMap (Column b) (PartialSQLExp b) -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HashMap.member (ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
columnInfo) (UpdPermInfo b -> HashMap (Column b) (PartialSQLExp b)
forall (b :: BackendType). UpdPermInfo b -> PreSetColsPartial b
upiSet UpdPermInfo b
permissions))
    isUpdatable Maybe (UpdPermInfo b)
Nothing ColumnInfo b
_ = Bool
False