module Hasura.RQL.DDL.Schema.Cache.Fields (addNonColumnFields) where

import Data.Aeson
import Data.Align (align)
import Data.HashMap.Strict.Extended qualified as HashMap
import Data.HashSet qualified as HS
import Data.Sequence qualified as Seq
import Data.Text.Extended
import Data.These (These (..))
import Hasura.Base.Error
import Hasura.Function.API
import Hasura.Function.Cache
import Hasura.Prelude
import Hasura.RQL.DDL.ComputedField
import Hasura.RQL.DDL.RemoteRelationship
import Hasura.RQL.DDL.Schema.Cache.Common
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.ComputedField
import Hasura.RQL.Types.Metadata
import Hasura.RQL.Types.Metadata.Backend
import Hasura.RQL.Types.Metadata.Object
import Hasura.RQL.Types.Relationships.Local
import Hasura.RQL.Types.Relationships.Remote
import Hasura.RQL.Types.SchemaCache
import Hasura.RQL.Types.SchemaCache.Build
import Hasura.RQL.Types.SchemaCacheTypes
import Hasura.SQL.AnyBackend qualified as AB
import Hasura.Table.Cache
import Language.GraphQL.Draft.Syntax qualified as G

addNonColumnFields ::
  forall b m.
  ( MonadWriter (Seq CollectItem) m,
    BackendMetadata b
  ) =>
  HashMap SourceName (AB.AnyBackend PartiallyResolvedSource) ->
  SourceName ->
  SourceConfig b ->
  HashMap (TableName b) (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b)) ->
  FieldInfoMap (StructuredColumnInfo b) ->
  PartiallyResolvedRemoteSchemaMap ->
  DBFunctionsMetadata b ->
  NonColumnTableInputs b ->
  m (FieldInfoMap (FieldInfo b))
addNonColumnFields :: forall (b :: BackendType) (m :: * -> *).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashMap SourceName (AnyBackend PartiallyResolvedSource)
-> SourceName
-> SourceConfig b
-> HashMap
     (TableName b)
     (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
-> FieldInfoMap (StructuredColumnInfo b)
-> PartiallyResolvedRemoteSchemaMap
-> DBFunctionsMetadata b
-> NonColumnTableInputs b
-> m (FieldInfoMap (FieldInfo b))
addNonColumnFields HashMap SourceName (AnyBackend PartiallyResolvedSource)
allSources SourceName
sourceName SourceConfig b
sourceConfig HashMap
  (TableName b)
  (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
rawTableInfos FieldInfoMap (StructuredColumnInfo b)
columns PartiallyResolvedRemoteSchemaMap
remoteSchemaMap DBFunctionsMetadata b
pgFunctions NonColumnTableInputs {[RemoteRelationship]
[ObjRelDef b]
[ArrRelDef b]
[ComputedFieldMetadata b]
TableName b
_nctiTable :: TableName b
_nctiObjectRelationships :: [ObjRelDef b]
_nctiArrayRelationships :: [ArrRelDef b]
_nctiComputedFields :: [ComputedFieldMetadata b]
_nctiRemoteRelationships :: [RemoteRelationship]
_nctiTable :: forall (b :: BackendType). NonColumnTableInputs b -> TableName b
_nctiObjectRelationships :: forall (b :: BackendType). NonColumnTableInputs b -> [ObjRelDef b]
_nctiArrayRelationships :: forall (b :: BackendType). NonColumnTableInputs b -> [ArrRelDef b]
_nctiComputedFields :: forall (b :: BackendType).
NonColumnTableInputs b -> [ComputedFieldMetadata b]
_nctiRemoteRelationships :: forall (b :: BackendType).
NonColumnTableInputs b -> [RemoteRelationship]
..} = do
  HashMap RelName (RelInfo b, MetadataObject)
objectRelationshipInfos <-
    (ObjRelDef b -> RelName)
-> (ObjRelDef b -> MetadataObject)
-> (ObjRelDef b -> m (Maybe (RelInfo b)))
-> [ObjRelDef b]
-> m (HashMap RelName (RelInfo b, MetadataObject))
forall (m :: * -> *) k a b.
(MonadWriter (Seq CollectItem) m, Hashable k) =>
(a -> k)
-> (a -> MetadataObject)
-> (a -> m (Maybe b))
-> [a]
-> m (HashMap k (b, MetadataObject))
buildInfoMapPreservingMetadataM
      ObjRelDef b -> RelName
forall a. RelDef a -> RelName
_rdName
      (forall (b :: BackendType) a.
(ToJSON a, Backend b) =>
RelType -> SourceName -> TableName b -> RelDef a -> MetadataObject
mkRelationshipMetadataObject @b RelType
ObjRel SourceName
sourceName TableName b
_nctiTable)
      (HashMap (TableName b) (HashSet (ForeignKey b))
-> SourceName
-> SourceConfig b
-> TableName b
-> ObjRelDef b
-> m (Maybe (RelInfo b))
forall (m :: * -> *) (b :: BackendType).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashMap (TableName b) (HashSet (ForeignKey b))
-> SourceName
-> SourceConfig b
-> TableName b
-> ObjRelDef b
-> m (Maybe (RelInfo b))
buildObjectRelationship (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b)
-> HashSet (ForeignKey b)
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> HashSet (ForeignKey b)
_tciForeignKeys (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b)
 -> HashSet (ForeignKey b))
-> HashMap
     (TableName b)
     (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
-> HashMap (TableName b) (HashSet (ForeignKey b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashMap
  (TableName b)
  (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
rawTableInfos) SourceName
sourceName SourceConfig b
sourceConfig TableName b
_nctiTable)
      [ObjRelDef b]
_nctiObjectRelationships

  HashMap RelName (RelInfo b, MetadataObject)
arrayRelationshipInfos <-
    (ArrRelDef b -> RelName)
-> (ArrRelDef b -> MetadataObject)
-> (ArrRelDef b -> m (Maybe (RelInfo b)))
-> [ArrRelDef b]
-> m (HashMap RelName (RelInfo b, MetadataObject))
forall (m :: * -> *) k a b.
(MonadWriter (Seq CollectItem) m, Hashable k) =>
(a -> k)
-> (a -> MetadataObject)
-> (a -> m (Maybe b))
-> [a]
-> m (HashMap k (b, MetadataObject))
buildInfoMapPreservingMetadataM
      ArrRelDef b -> RelName
forall a. RelDef a -> RelName
_rdName
      (forall (b :: BackendType) a.
(ToJSON a, Backend b) =>
RelType -> SourceName -> TableName b -> RelDef a -> MetadataObject
mkRelationshipMetadataObject @b RelType
ArrRel SourceName
sourceName TableName b
_nctiTable)
      (HashMap (TableName b) (HashSet (ForeignKey b))
-> SourceName
-> SourceConfig b
-> TableName b
-> ArrRelDef b
-> m (Maybe (RelInfo b))
forall (m :: * -> *) (b :: BackendType).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashMap (TableName b) (HashSet (ForeignKey b))
-> SourceName
-> SourceConfig b
-> TableName b
-> ArrRelDef b
-> m (Maybe (RelInfo b))
buildArrayRelationship (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b)
-> HashSet (ForeignKey b)
forall (b :: BackendType) field primaryKeyColumn.
TableCoreInfoG b field primaryKeyColumn -> HashSet (ForeignKey b)
_tciForeignKeys (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b)
 -> HashSet (ForeignKey b))
-> HashMap
     (TableName b)
     (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
-> HashMap (TableName b) (HashSet (ForeignKey b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashMap
  (TableName b)
  (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
rawTableInfos) SourceName
sourceName SourceConfig b
sourceConfig TableName b
_nctiTable)
      [ArrRelDef b]
_nctiArrayRelationships

  let relationshipInfos :: HashMap RelName (RelInfo b, MetadataObject)
relationshipInfos = HashMap RelName (RelInfo b, MetadataObject)
objectRelationshipInfos HashMap RelName (RelInfo b, MetadataObject)
-> HashMap RelName (RelInfo b, MetadataObject)
-> HashMap RelName (RelInfo b, MetadataObject)
forall a. Semigroup a => a -> a -> a
<> HashMap RelName (RelInfo b, MetadataObject)
arrayRelationshipInfos
      scalarColumns :: HashMap FieldName (ColumnInfo b)
scalarColumns = (StructuredColumnInfo b -> Maybe (ColumnInfo b))
-> FieldInfoMap (StructuredColumnInfo b)
-> HashMap FieldName (ColumnInfo b)
forall v1 v2 k. (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
HashMap.mapMaybe StructuredColumnInfo b -> Maybe (ColumnInfo b)
forall (b :: BackendType).
StructuredColumnInfo b -> Maybe (ColumnInfo b)
toScalarColumnInfo FieldInfoMap (StructuredColumnInfo b)
columns

  HashMap ComputedFieldName (ComputedFieldInfo b, MetadataObject)
computedFieldInfos <-
    (ComputedFieldMetadata b -> ComputedFieldName)
-> (ComputedFieldMetadata b -> MetadataObject)
-> (ComputedFieldMetadata b -> m (Maybe (ComputedFieldInfo b)))
-> [ComputedFieldMetadata b]
-> m (HashMap
        ComputedFieldName (ComputedFieldInfo b, MetadataObject))
forall (m :: * -> *) k a b.
(MonadWriter (Seq CollectItem) m, Hashable k) =>
(a -> k)
-> (a -> MetadataObject)
-> (a -> m (Maybe b))
-> [a]
-> m (HashMap k (b, MetadataObject))
buildInfoMapPreservingMetadataM
      ComputedFieldMetadata b -> ComputedFieldName
forall (b :: BackendType).
ComputedFieldMetadata b -> ComputedFieldName
_cfmName
      (SourceName
-> TableName b -> ComputedFieldMetadata b -> MetadataObject
forall (b :: BackendType).
Backend b =>
SourceName
-> TableName b -> ComputedFieldMetadata b -> MetadataObject
mkComputedFieldMetadataObject SourceName
sourceName TableName b
_nctiTable)
      (HashSet (TableName b)
-> HashSet (Column b)
-> SourceName
-> DBFunctionsMetadata b
-> TableName b
-> ComputedFieldMetadata b
-> m (Maybe (ComputedFieldInfo b))
forall (b :: BackendType) (m :: * -> *).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashSet (TableName b)
-> HashSet (Column b)
-> SourceName
-> DBFunctionsMetadata b
-> TableName b
-> ComputedFieldMetadata b
-> m (Maybe (ComputedFieldInfo b))
buildComputedField ([TableName b] -> HashSet (TableName b)
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HS.fromList ([TableName b] -> HashSet (TableName b))
-> [TableName b] -> HashSet (TableName b)
forall a b. (a -> b) -> a -> b
$ HashMap
  (TableName b)
  (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
-> [TableName b]
forall k v. HashMap k v -> [k]
HashMap.keys HashMap
  (TableName b)
  (TableCoreInfoG b (StructuredColumnInfo b) (ColumnInfo b))
rawTableInfos) ([Column b] -> HashSet (Column b)
forall a. (Eq a, Hashable a) => [a] -> HashSet a
HS.fromList ([Column b] -> HashSet (Column b))
-> [Column b] -> HashSet (Column b)
forall a b. (a -> b) -> a -> b
$ (ColumnInfo b -> Column b) -> [ColumnInfo b] -> [Column b]
forall a b. (a -> b) -> [a] -> [b]
map ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ([ColumnInfo b] -> [Column b]) -> [ColumnInfo b] -> [Column b]
forall a b. (a -> b) -> a -> b
$ HashMap FieldName (ColumnInfo b) -> [ColumnInfo b]
forall k v. HashMap k v -> [v]
HashMap.elems HashMap FieldName (ColumnInfo b)
scalarColumns) SourceName
sourceName DBFunctionsMetadata b
pgFunctions TableName b
_nctiTable)
      [ComputedFieldMetadata b]
_nctiComputedFields
  -- the fields that can be used for defining join conditions to other sources/remote schemas:
  -- 1. all columns
  -- 2. computed fields which don't expect arguments other than the table row and user session
  let lhsJoinFields :: HashMap FieldName (DBJoinField b)
lhsJoinFields =
        let columnFields :: HashMap FieldName (DBJoinField b)
columnFields = HashMap FieldName (ColumnInfo b)
scalarColumns HashMap FieldName (ColumnInfo b)
-> (ColumnInfo b -> DBJoinField b)
-> HashMap FieldName (DBJoinField b)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \ColumnInfo b
columnInfo -> Column b -> ColumnType b -> DBJoinField b
forall (b :: BackendType).
Column b -> ColumnType b -> DBJoinField b
JoinColumn (ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
columnInfo) (ColumnInfo b -> ColumnType b
forall (b :: BackendType). ColumnInfo b -> ColumnType b
ciType ColumnInfo b
columnInfo)
            computedFields :: HashMap FieldName (DBJoinField b)
computedFields = [(FieldName, DBJoinField b)] -> HashMap FieldName (DBJoinField b)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
              ([(FieldName, DBJoinField b)] -> HashMap FieldName (DBJoinField b))
-> [(FieldName, DBJoinField b)]
-> HashMap FieldName (DBJoinField b)
forall a b. (a -> b) -> a -> b
$ (((ComputedFieldName, (ComputedFieldInfo b, MetadataObject))
  -> Maybe (FieldName, DBJoinField b))
 -> [(ComputedFieldName, (ComputedFieldInfo b, MetadataObject))]
 -> [(FieldName, DBJoinField b)])
-> [(ComputedFieldName, (ComputedFieldInfo b, MetadataObject))]
-> ((ComputedFieldName, (ComputedFieldInfo b, MetadataObject))
    -> Maybe (FieldName, DBJoinField b))
-> [(FieldName, DBJoinField b)]
forall a b c. (a -> b -> c) -> b -> a -> c
flip ((ComputedFieldName, (ComputedFieldInfo b, MetadataObject))
 -> Maybe (FieldName, DBJoinField b))
-> [(ComputedFieldName, (ComputedFieldInfo b, MetadataObject))]
-> [(FieldName, DBJoinField b)]
forall a b. (a -> Maybe b) -> [a] -> [b]
forall (f :: * -> *) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe (HashMap ComputedFieldName (ComputedFieldInfo b, MetadataObject)
-> [(ComputedFieldName, (ComputedFieldInfo b, MetadataObject))]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap ComputedFieldName (ComputedFieldInfo b, MetadataObject)
computedFieldInfos)
              (((ComputedFieldName, (ComputedFieldInfo b, MetadataObject))
  -> Maybe (FieldName, DBJoinField b))
 -> [(FieldName, DBJoinField b)])
-> ((ComputedFieldName, (ComputedFieldInfo b, MetadataObject))
    -> Maybe (FieldName, DBJoinField b))
-> [(FieldName, DBJoinField b)]
forall a b. (a -> b) -> a -> b
$ \(ComputedFieldName
cfName, (ComputedFieldInfo {Maybe Text
ComputedFieldName
ComputedFieldReturn b
XComputedField b
ComputedFieldFunction b
_cfiXComputedFieldInfo :: XComputedField b
_cfiName :: ComputedFieldName
_cfiFunction :: ComputedFieldFunction b
_cfiReturnType :: ComputedFieldReturn b
_cfiDescription :: Maybe Text
_cfiXComputedFieldInfo :: forall (b :: BackendType). ComputedFieldInfo b -> XComputedField b
_cfiName :: forall (b :: BackendType). ComputedFieldInfo b -> ComputedFieldName
_cfiFunction :: forall (b :: BackendType).
ComputedFieldInfo b -> ComputedFieldFunction b
_cfiReturnType :: forall (b :: BackendType).
ComputedFieldInfo b -> ComputedFieldReturn b
_cfiDescription :: forall (b :: BackendType). ComputedFieldInfo b -> Maybe Text
..}, MetadataObject
_)) -> do
                ScalarType b
scalarType <- case forall (b :: BackendType).
Backend b =>
ComputedFieldReturn b -> ComputedFieldReturnType b
computedFieldReturnType @b ComputedFieldReturn b
_cfiReturnType of
                  ReturnsScalar ScalarType b
ty -> ScalarType b -> Maybe (ScalarType b)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ScalarType b
ty
                  ReturnsTable {} -> Maybe (ScalarType b)
forall a. Maybe a
Nothing
                  ReturnsOthers {} -> Maybe (ScalarType b)
forall a. Maybe a
Nothing
                let ComputedFieldFunction {Maybe PGDescription
Seq (FunctionArgument b)
FunctionName b
ComputedFieldImplicitArguments b
_cffName :: FunctionName b
_cffInputArgs :: Seq (FunctionArgument b)
_cffComputedFieldImplicitArgs :: ComputedFieldImplicitArguments b
_cffDescription :: Maybe PGDescription
_cffName :: forall (b :: BackendType).
ComputedFieldFunction b -> FunctionName b
_cffInputArgs :: forall (b :: BackendType).
ComputedFieldFunction b -> Seq (FunctionArgument b)
_cffComputedFieldImplicitArgs :: forall (b :: BackendType).
ComputedFieldFunction b -> ComputedFieldImplicitArguments b
_cffDescription :: forall (b :: BackendType).
ComputedFieldFunction b -> Maybe PGDescription
..} = ComputedFieldFunction b
_cfiFunction
                case Seq (FunctionArgument b) -> [FunctionArgument b]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq (FunctionArgument b)
_cffInputArgs of
                  [] ->
                    (FieldName, DBJoinField b) -> Maybe (FieldName, DBJoinField b)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
                      ((FieldName, DBJoinField b) -> Maybe (FieldName, DBJoinField b))
-> (FieldName, DBJoinField b) -> Maybe (FieldName, DBJoinField b)
forall a b. (a -> b) -> a -> b
$ (ComputedFieldName -> FieldName
fromComputedField ComputedFieldName
cfName,)
                      (DBJoinField b -> (FieldName, DBJoinField b))
-> DBJoinField b -> (FieldName, DBJoinField b)
forall a b. (a -> b) -> a -> b
$ ScalarComputedField b -> DBJoinField b
forall (b :: BackendType). ScalarComputedField b -> DBJoinField b
JoinComputedField
                      (ScalarComputedField b -> DBJoinField b)
-> ScalarComputedField b -> DBJoinField b
forall a b. (a -> b) -> a -> b
$ XComputedField b
-> ComputedFieldName
-> FunctionName b
-> ComputedFieldImplicitArguments b
-> ScalarType b
-> ScalarComputedField b
forall (b :: BackendType).
XComputedField b
-> ComputedFieldName
-> FunctionName b
-> ComputedFieldImplicitArguments b
-> ScalarType b
-> ScalarComputedField b
ScalarComputedField
                        XComputedField b
_cfiXComputedFieldInfo
                        ComputedFieldName
_cfiName
                        FunctionName b
_cffName
                        ComputedFieldImplicitArguments b
_cffComputedFieldImplicitArgs
                        ScalarType b
scalarType
                  [FunctionArgument b]
_ -> Maybe (FieldName, DBJoinField b)
forall a. Maybe a
Nothing
         in HashMap FieldName (DBJoinField b)
-> HashMap FieldName (DBJoinField b)
-> HashMap FieldName (DBJoinField b)
forall k v.
(Eq k, Hashable k) =>
HashMap k v -> HashMap k v -> HashMap k v
HashMap.union HashMap FieldName (DBJoinField b)
columnFields HashMap FieldName (DBJoinField b)
computedFields

  HashMap RelName (RemoteFieldInfo (DBJoinField b), MetadataObject)
rawRemoteRelationshipInfos <-
    (RemoteRelationship -> RelName)
-> (RemoteRelationship -> MetadataObject)
-> (RemoteRelationship
    -> m (Maybe (RemoteFieldInfo (DBJoinField b))))
-> [RemoteRelationship]
-> m (HashMap
        RelName (RemoteFieldInfo (DBJoinField b), MetadataObject))
forall (m :: * -> *) k a b.
(MonadWriter (Seq CollectItem) m, Hashable k) =>
(a -> k)
-> (a -> MetadataObject)
-> (a -> m (Maybe b))
-> [a]
-> m (HashMap k (b, MetadataObject))
buildInfoMapPreservingMetadataM
      RemoteRelationship -> RelName
forall definition. RemoteRelationshipG definition -> RelName
_rrName
      (forall (b :: BackendType).
Backend b =>
SourceName -> TableName b -> RemoteRelationship -> MetadataObject
mkRemoteRelationshipMetadataObject @b SourceName
sourceName TableName b
_nctiTable)
      (HashMap SourceName (AnyBackend PartiallyResolvedSource)
-> HashMap FieldName (DBJoinField b)
-> PartiallyResolvedRemoteSchemaMap
-> SourceName
-> TableName b
-> RemoteRelationship
-> m (Maybe (RemoteFieldInfo (DBJoinField b)))
forall (b :: BackendType) (m :: * -> *).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashMap SourceName (AnyBackend PartiallyResolvedSource)
-> HashMap FieldName (DBJoinField b)
-> PartiallyResolvedRemoteSchemaMap
-> SourceName
-> TableName b
-> RemoteRelationship
-> m (Maybe (RemoteFieldInfo (DBJoinField b)))
buildRemoteRelationship HashMap SourceName (AnyBackend PartiallyResolvedSource)
allSources HashMap FieldName (DBJoinField b)
lhsJoinFields PartiallyResolvedRemoteSchemaMap
remoteSchemaMap SourceName
sourceName TableName b
_nctiTable)
      [RemoteRelationship]
_nctiRemoteRelationships

  let relationshipFields :: HashMap FieldName (RelInfo b, MetadataObject)
relationshipFields = (RelName -> FieldName)
-> HashMap RelName (RelInfo b, MetadataObject)
-> HashMap FieldName (RelInfo b, MetadataObject)
forall k2 k1 v.
(Eq k2, Hashable k2) =>
(k1 -> k2) -> HashMap k1 v -> HashMap k2 v
mapKeys RelName -> FieldName
fromRel HashMap RelName (RelInfo b, MetadataObject)
relationshipInfos
      computedFieldFields :: HashMap FieldName (ComputedFieldInfo b, MetadataObject)
computedFieldFields = (ComputedFieldName -> FieldName)
-> HashMap ComputedFieldName (ComputedFieldInfo b, MetadataObject)
-> HashMap FieldName (ComputedFieldInfo b, MetadataObject)
forall k2 k1 v.
(Eq k2, Hashable k2) =>
(k1 -> k2) -> HashMap k1 v -> HashMap k2 v
mapKeys ComputedFieldName -> FieldName
fromComputedField HashMap ComputedFieldName (ComputedFieldInfo b, MetadataObject)
computedFieldInfos
      remoteRelationshipFields :: HashMap FieldName (RemoteFieldInfo (DBJoinField b), MetadataObject)
remoteRelationshipFields = (RelName -> FieldName)
-> HashMap
     RelName (RemoteFieldInfo (DBJoinField b), MetadataObject)
-> HashMap
     FieldName (RemoteFieldInfo (DBJoinField b), MetadataObject)
forall k2 k1 v.
(Eq k2, Hashable k2) =>
(k1 -> k2) -> HashMap k1 v -> HashMap k2 v
mapKeys RelName -> FieldName
fromRemoteRelationship HashMap RelName (RemoteFieldInfo (DBJoinField b), MetadataObject)
rawRemoteRelationshipInfos

  -- Validation phase

  -- First, check for conflicts between non-column fields, since we can raise a better error
  -- message in terms of the two metadata objects that define them.
  let relationshipAndComputedFields :: HashMap
  FieldName
  (These
     (RelInfo b, MetadataObject) (ComputedFieldInfo b, MetadataObject))
relationshipAndComputedFields = HashMap FieldName (RelInfo b, MetadataObject)
-> HashMap FieldName (ComputedFieldInfo b, MetadataObject)
-> HashMap
     FieldName
     (These
        (RelInfo b, MetadataObject) (ComputedFieldInfo b, MetadataObject))
forall a b.
HashMap FieldName a
-> HashMap FieldName b -> HashMap FieldName (These a b)
forall (f :: * -> *) a b.
Semialign f =>
f a -> f b -> f (These a b)
align HashMap FieldName (RelInfo b, MetadataObject)
relationshipFields HashMap FieldName (ComputedFieldInfo b, MetadataObject)
computedFieldFields
  HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
step1 <- (FieldName
 -> These
      (RelInfo b, MetadataObject) (ComputedFieldInfo b, MetadataObject)
 -> m (Maybe (FieldInfo b, MetadataObject)))
-> HashMap
     FieldName
     (These
        (RelInfo b, MetadataObject) (ComputedFieldInfo b, MetadataObject))
-> m (HashMap FieldName (Maybe (FieldInfo b, MetadataObject)))
forall (f :: * -> *) k v1 v2.
Applicative f =>
(k -> v1 -> f v2) -> HashMap k v1 -> f (HashMap k v2)
HashMap.traverseWithKey ((RelInfo b -> FieldInfo b)
-> (ComputedFieldInfo b -> FieldInfo b)
-> FieldName
-> These
     (RelInfo b, MetadataObject) (ComputedFieldInfo b, MetadataObject)
-> m (Maybe (FieldInfo b, MetadataObject))
forall {f :: * -> *} {t} {t} {a} {t}.
(MonadWriter (Seq CollectItem) f, ToTxt t) =>
(t -> a)
-> (t -> a)
-> t
-> These (t, MetadataObject) (t, MetadataObject)
-> f (Maybe (a, MetadataObject))
noFieldConflicts RelInfo b -> FieldInfo b
forall (b :: BackendType). RelInfo b -> FieldInfo b
FIRelationship ComputedFieldInfo b -> FieldInfo b
forall (b :: BackendType). ComputedFieldInfo b -> FieldInfo b
FIComputedField) HashMap
  FieldName
  (These
     (RelInfo b, MetadataObject) (ComputedFieldInfo b, MetadataObject))
relationshipAndComputedFields
  -- Second, align with remote relationship fields
  let nonColumnFields :: HashMap
  FieldName
  (These
     (FieldInfo b, MetadataObject)
     (RemoteFieldInfo (DBJoinField b), MetadataObject))
nonColumnFields = HashMap FieldName (FieldInfo b, MetadataObject)
-> HashMap
     FieldName (RemoteFieldInfo (DBJoinField b), MetadataObject)
-> HashMap
     FieldName
     (These
        (FieldInfo b, MetadataObject)
        (RemoteFieldInfo (DBJoinField b), MetadataObject))
forall a b.
HashMap FieldName a
-> HashMap FieldName b -> HashMap FieldName (These a b)
forall (f :: * -> *) a b.
Semialign f =>
f a -> f b -> f (These a b)
align (HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
-> HashMap FieldName (FieldInfo b, MetadataObject)
forall a. HashMap FieldName (Maybe a) -> HashMap FieldName a
forall (f :: * -> *) a. Filterable f => f (Maybe a) -> f a
catMaybes HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
step1) HashMap FieldName (RemoteFieldInfo (DBJoinField b), MetadataObject)
remoteRelationshipFields
  HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
step2 <- (FieldName
 -> These
      (FieldInfo b, MetadataObject)
      (RemoteFieldInfo (DBJoinField b), MetadataObject)
 -> m (Maybe (FieldInfo b, MetadataObject)))
-> HashMap
     FieldName
     (These
        (FieldInfo b, MetadataObject)
        (RemoteFieldInfo (DBJoinField b), MetadataObject))
-> m (HashMap FieldName (Maybe (FieldInfo b, MetadataObject)))
forall (f :: * -> *) k v1 v2.
Applicative f =>
(k -> v1 -> f v2) -> HashMap k v1 -> f (HashMap k v2)
HashMap.traverseWithKey ((FieldInfo b -> FieldInfo b)
-> (RemoteFieldInfo (DBJoinField b) -> FieldInfo b)
-> FieldName
-> These
     (FieldInfo b, MetadataObject)
     (RemoteFieldInfo (DBJoinField b), MetadataObject)
-> m (Maybe (FieldInfo b, MetadataObject))
forall {f :: * -> *} {t} {t} {a} {t}.
(MonadWriter (Seq CollectItem) f, ToTxt t) =>
(t -> a)
-> (t -> a)
-> t
-> These (t, MetadataObject) (t, MetadataObject)
-> f (Maybe (a, MetadataObject))
noFieldConflicts FieldInfo b -> FieldInfo b
forall a. a -> a
id RemoteFieldInfo (DBJoinField b) -> FieldInfo b
forall (b :: BackendType).
RemoteFieldInfo (DBJoinField b) -> FieldInfo b
FIRemoteRelationship) HashMap
  FieldName
  (These
     (FieldInfo b, MetadataObject)
     (RemoteFieldInfo (DBJoinField b), MetadataObject))
nonColumnFields
  -- Next, check for conflicts with custom field names. This is easiest to do before merging with
  -- the column info itself because we have access to the information separately, and custom field
  -- names are not currently stored as a separate map (but maybe should be!).
  HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
step3 <- HashMap FieldName (FieldInfo b, MetadataObject)
-> m (HashMap FieldName (Maybe (FieldInfo b, MetadataObject)))
noCustomFieldConflicts (HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
-> HashMap FieldName (FieldInfo b, MetadataObject)
forall a. HashMap FieldName (Maybe a) -> HashMap FieldName a
forall (f :: * -> *) a. Filterable f => f (Maybe a) -> f a
catMaybes HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
step2)
  -- Finally, check for conflicts with the columns themselves.
  let allFields :: HashMap
  FieldName
  (These (StructuredColumnInfo b) (FieldInfo b, MetadataObject))
allFields = FieldInfoMap (StructuredColumnInfo b)
-> HashMap FieldName (FieldInfo b, MetadataObject)
-> HashMap
     FieldName
     (These (StructuredColumnInfo b) (FieldInfo b, MetadataObject))
forall a b.
HashMap FieldName a
-> HashMap FieldName b -> HashMap FieldName (These a b)
forall (f :: * -> *) a b.
Semialign f =>
f a -> f b -> f (These a b)
align FieldInfoMap (StructuredColumnInfo b)
columns (HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
-> HashMap FieldName (FieldInfo b, MetadataObject)
forall a. HashMap FieldName (Maybe a) -> HashMap FieldName a
forall (f :: * -> *) a. Filterable f => f (Maybe a) -> f a
catMaybes HashMap FieldName (Maybe (FieldInfo b, MetadataObject))
step3)
  (These (StructuredColumnInfo b) (FieldInfo b, MetadataObject)
 -> m (FieldInfo b))
-> HashMap
     FieldName
     (These (StructuredColumnInfo b) (FieldInfo b, MetadataObject))
-> m (FieldInfoMap (FieldInfo b))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> HashMap FieldName a -> f (HashMap FieldName b)
traverse These (StructuredColumnInfo b) (FieldInfo b, MetadataObject)
-> m (FieldInfo b)
forall {b :: BackendType}.
These (StructuredColumnInfo b) (FieldInfo b, MetadataObject)
-> m (FieldInfo b)
noColumnConflicts HashMap
  FieldName
  (These (StructuredColumnInfo b) (FieldInfo b, MetadataObject))
allFields
  where
    noFieldConflicts :: (t -> a)
-> (t -> a)
-> t
-> These (t, MetadataObject) (t, MetadataObject)
-> f (Maybe (a, MetadataObject))
noFieldConflicts t -> a
this t -> a
that t
fieldName = \case
      This (t
thisField, MetadataObject
metadata) -> Maybe (a, MetadataObject) -> f (Maybe (a, MetadataObject))
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (a, MetadataObject) -> f (Maybe (a, MetadataObject)))
-> Maybe (a, MetadataObject) -> f (Maybe (a, MetadataObject))
forall a b. (a -> b) -> a -> b
$ (a, MetadataObject) -> Maybe (a, MetadataObject)
forall a. a -> Maybe a
Just (t -> a
this t
thisField, MetadataObject
metadata)
      That (t
thatField, MetadataObject
metadata) -> Maybe (a, MetadataObject) -> f (Maybe (a, MetadataObject))
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (a, MetadataObject) -> f (Maybe (a, MetadataObject)))
-> Maybe (a, MetadataObject) -> f (Maybe (a, MetadataObject))
forall a b. (a -> b) -> a -> b
$ (a, MetadataObject) -> Maybe (a, MetadataObject)
forall a. a -> Maybe a
Just (t -> a
that t
thatField, MetadataObject
metadata)
      These (t
_, MetadataObject
thisMetadata) (t
_, MetadataObject
thatMetadata) -> do
        Seq CollectItem -> f ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell
          (Seq CollectItem -> f ()) -> Seq CollectItem -> f ()
forall a b. (a -> b) -> a -> b
$ CollectItem -> Seq CollectItem
forall a. a -> Seq a
Seq.singleton
          (CollectItem -> Seq CollectItem) -> CollectItem -> Seq CollectItem
forall a b. (a -> b) -> a -> b
$ InconsistentMetadata -> CollectItem
CollectInconsistentMetadata
          (InconsistentMetadata -> CollectItem)
-> InconsistentMetadata -> CollectItem
forall a b. (a -> b) -> a -> b
$ Text -> [MetadataObject] -> InconsistentMetadata
ConflictingObjects
            (Text
"conflicting definitions for field " Text -> t -> Text
forall t. ToTxt t => Text -> t -> Text
<>> t
fieldName)
            [MetadataObject
thisMetadata, MetadataObject
thatMetadata]
        Maybe (a, MetadataObject) -> f (Maybe (a, MetadataObject))
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (a, MetadataObject)
forall a. Maybe a
Nothing

    noCustomFieldConflicts :: HashMap FieldName (FieldInfo b, MetadataObject)
-> m (HashMap FieldName (Maybe (FieldInfo b, MetadataObject)))
noCustomFieldConflicts HashMap FieldName (FieldInfo b, MetadataObject)
nonColumnFields = do
      let columnsByGQLName :: HashMap Name (StructuredColumnInfo b)
columnsByGQLName = (StructuredColumnInfo b -> Name)
-> [StructuredColumnInfo b]
-> HashMap Name (StructuredColumnInfo b)
forall k a. Hashable k => (a -> k) -> [a] -> HashMap k a
mapFromL StructuredColumnInfo b -> Name
forall (b :: BackendType). StructuredColumnInfo b -> Name
structuredColumnInfoName ([StructuredColumnInfo b] -> HashMap Name (StructuredColumnInfo b))
-> [StructuredColumnInfo b]
-> HashMap Name (StructuredColumnInfo b)
forall a b. (a -> b) -> a -> b
$ FieldInfoMap (StructuredColumnInfo b) -> [StructuredColumnInfo b]
forall k v. HashMap k v -> [v]
HashMap.elems FieldInfoMap (StructuredColumnInfo b)
columns
      HashMap FieldName (FieldInfo b, MetadataObject)
-> ((FieldInfo b, MetadataObject)
    -> m (Maybe (FieldInfo b, MetadataObject)))
-> m (HashMap FieldName (Maybe (FieldInfo b, MetadataObject)))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for HashMap FieldName (FieldInfo b, MetadataObject)
nonColumnFields \(FieldInfo b
fieldInfo, MetadataObject
metadata) -> MetadataObject
-> ExceptT QErr m (FieldInfo b, MetadataObject)
-> m (Maybe (FieldInfo b, MetadataObject))
forall (m :: * -> *) a.
MonadWriter (Seq CollectItem) m =>
MetadataObject -> ExceptT QErr m a -> m (Maybe a)
withRecordInconsistencyM MetadataObject
metadata do
        [Name] -> (Name -> ExceptT QErr m ()) -> ExceptT QErr m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (FieldInfo b -> [Name]
forall (b :: BackendType). FieldInfo b -> [Name]
fieldInfoGraphQLNames FieldInfo b
fieldInfo) \Name
fieldGQLName ->
          case Name
-> HashMap Name (StructuredColumnInfo b)
-> Maybe (StructuredColumnInfo b)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Name
fieldGQLName HashMap Name (StructuredColumnInfo b)
columnsByGQLName of
            -- Only raise an error if the GQL name isn’t the same as the Postgres column name.
            -- If they are the same, `noColumnConflicts` will catch it, and it will produce a
            -- more useful error message.
            Just StructuredColumnInfo b
columnInfo
              | Column b -> Text
forall a. ToTxt a => a -> Text
toTxt (StructuredColumnInfo b -> Column b
forall (b :: BackendType). StructuredColumnInfo b -> Column b
structuredColumnInfoColumn StructuredColumnInfo b
columnInfo) Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Name -> Text
G.unName Name
fieldGQLName ->
                  Code -> Text -> ExceptT QErr m ()
forall (m :: * -> *) a. QErrM m => Code -> Text -> m a
throw400 Code
AlreadyExists
                    (Text -> ExceptT QErr m ()) -> Text -> ExceptT QErr m ()
forall a b. (a -> b) -> a -> b
$ Text
"field definition conflicts with custom field name for postgres column "
                    Text -> Column b -> Text
forall t. ToTxt t => Text -> t -> Text
<>> StructuredColumnInfo b -> Column b
forall (b :: BackendType). StructuredColumnInfo b -> Column b
structuredColumnInfoColumn StructuredColumnInfo b
columnInfo
            Maybe (StructuredColumnInfo b)
_ -> () -> ExceptT QErr m ()
forall a. a -> ExceptT QErr m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        (FieldInfo b, MetadataObject)
-> ExceptT QErr m (FieldInfo b, MetadataObject)
forall a. a -> ExceptT QErr m a
forall (m :: * -> *) a. Monad m => a -> m a
return (FieldInfo b
fieldInfo, MetadataObject
metadata)

    noColumnConflicts :: These (StructuredColumnInfo b) (FieldInfo b, MetadataObject)
-> m (FieldInfo b)
noColumnConflicts = \case
      This StructuredColumnInfo b
columnInfo -> FieldInfo b -> m (FieldInfo b)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldInfo b -> m (FieldInfo b)) -> FieldInfo b -> m (FieldInfo b)
forall a b. (a -> b) -> a -> b
$ StructuredColumnInfo b -> FieldInfo b
forall (b :: BackendType). StructuredColumnInfo b -> FieldInfo b
FIColumn StructuredColumnInfo b
columnInfo
      That (FieldInfo b
fieldInfo, MetadataObject
_) -> FieldInfo b -> m (FieldInfo b)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldInfo b -> m (FieldInfo b)) -> FieldInfo b -> m (FieldInfo b)
forall a b. (a -> b) -> a -> b
$ FieldInfo b
fieldInfo
      These StructuredColumnInfo b
columnInfo (FieldInfo b
_, MetadataObject
fieldMetadata) -> do
        Maybe Value -> MetadataObject -> Text -> m ()
forall (m :: * -> *).
MonadWriter (Seq CollectItem) m =>
Maybe Value -> MetadataObject -> Text -> m ()
recordInconsistencyM Maybe Value
forall a. Maybe a
Nothing MetadataObject
fieldMetadata Text
"field definition conflicts with postgres column"
        FieldInfo b -> m (FieldInfo b)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FieldInfo b -> m (FieldInfo b)) -> FieldInfo b -> m (FieldInfo b)
forall a b. (a -> b) -> a -> b
$ StructuredColumnInfo b -> FieldInfo b
forall (b :: BackendType). StructuredColumnInfo b -> FieldInfo b
FIColumn StructuredColumnInfo b
columnInfo

mkRelationshipMetadataObject ::
  forall b a.
  (ToJSON a, Backend b) =>
  RelType ->
  SourceName ->
  TableName b ->
  RelDef a ->
  MetadataObject
mkRelationshipMetadataObject :: forall (b :: BackendType) a.
(ToJSON a, Backend b) =>
RelType -> SourceName -> TableName b -> RelDef a -> MetadataObject
mkRelationshipMetadataObject RelType
relType SourceName
source TableName b
table RelDef a
relDef =
  let objectId :: MetadataObjId
objectId =
        SourceName -> AnyBackend SourceMetadataObjId -> MetadataObjId
MOSourceObjId SourceName
source
          (AnyBackend SourceMetadataObjId -> MetadataObjId)
-> AnyBackend SourceMetadataObjId -> MetadataObjId
forall a b. (a -> b) -> a -> b
$ SourceMetadataObjId b -> AnyBackend SourceMetadataObjId
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
AB.mkAnyBackend
          (SourceMetadataObjId b -> AnyBackend SourceMetadataObjId)
-> SourceMetadataObjId b -> AnyBackend SourceMetadataObjId
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
TableName b -> TableMetadataObjId -> SourceMetadataObjId b
SMOTableObj @b TableName b
table
          (TableMetadataObjId -> SourceMetadataObjId b)
-> TableMetadataObjId -> SourceMetadataObjId b
forall a b. (a -> b) -> a -> b
$ RelName -> RelType -> TableMetadataObjId
MTORel (RelDef a -> RelName
forall a. RelDef a -> RelName
_rdName RelDef a
relDef) RelType
relType
   in MetadataObjId -> Value -> MetadataObject
MetadataObject MetadataObjId
objectId (Value -> MetadataObject) -> Value -> MetadataObject
forall a b. (a -> b) -> a -> b
$ WithTable b (RelDef a) -> Value
forall a. ToJSON a => a -> Value
toJSON (WithTable b (RelDef a) -> Value)
-> WithTable b (RelDef a) -> Value
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType) a.
SourceName -> TableName b -> a -> WithTable b a
WithTable @b SourceName
source TableName b
table RelDef a
relDef

buildObjectRelationship ::
  ( MonadWriter (Seq CollectItem) m,
    BackendMetadata b
  ) =>
  HashMap (TableName b) (HashSet (ForeignKey b)) ->
  SourceName ->
  SourceConfig b ->
  TableName b ->
  ObjRelDef b ->
  m (Maybe (RelInfo b))
buildObjectRelationship :: forall (m :: * -> *) (b :: BackendType).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashMap (TableName b) (HashSet (ForeignKey b))
-> SourceName
-> SourceConfig b
-> TableName b
-> ObjRelDef b
-> m (Maybe (RelInfo b))
buildObjectRelationship HashMap (TableName b) (HashSet (ForeignKey b))
fkeysMap SourceName
sourceName SourceConfig b
sourceConfig TableName b
table ObjRelDef b
relDef = do
  let buildRelInfo :: ObjRelDef b -> Either QErr (RelInfo b, Seq SchemaDependency)
buildRelInfo = SourceConfig b
-> SourceName
-> HashMap (TableName b) (HashSet (ForeignKey b))
-> TableName b
-> ObjRelDef b
-> Either QErr (RelInfo b, Seq SchemaDependency)
forall (b :: BackendType) (m :: * -> *).
(BackendMetadata b, MonadError QErr m) =>
SourceConfig b
-> SourceName
-> HashMap (TableName b) (HashSet (ForeignKey b))
-> TableName b
-> ObjRelDef b
-> m (RelInfo b, Seq SchemaDependency)
forall (m :: * -> *).
MonadError QErr m =>
SourceConfig b
-> SourceName
-> HashMap (TableName b) (HashSet (ForeignKey b))
-> TableName b
-> ObjRelDef b
-> m (RelInfo b, Seq SchemaDependency)
buildObjectRelationshipInfo SourceConfig b
sourceConfig SourceName
sourceName HashMap (TableName b) (HashSet (ForeignKey b))
fkeysMap TableName b
table
  SourceName
-> TableName b
-> (ObjRelDef b -> Either QErr (RelInfo b, Seq SchemaDependency))
-> RelType
-> ObjRelDef b
-> m (Maybe (RelInfo b))
forall (m :: * -> *) (b :: BackendType) a.
(MonadWriter (Seq CollectItem) m, ToJSON a, Backend b) =>
SourceName
-> TableName b
-> (RelDef a -> Either QErr (RelInfo b, Seq SchemaDependency))
-> RelType
-> RelDef a
-> m (Maybe (RelInfo b))
buildRelationship SourceName
sourceName TableName b
table ObjRelDef b -> Either QErr (RelInfo b, Seq SchemaDependency)
buildRelInfo RelType
ObjRel ObjRelDef b
relDef

buildArrayRelationship ::
  ( MonadWriter (Seq CollectItem) m,
    BackendMetadata b
  ) =>
  HashMap (TableName b) (HashSet (ForeignKey b)) ->
  SourceName ->
  SourceConfig b ->
  TableName b ->
  ArrRelDef b ->
  m (Maybe (RelInfo b))
buildArrayRelationship :: forall (m :: * -> *) (b :: BackendType).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashMap (TableName b) (HashSet (ForeignKey b))
-> SourceName
-> SourceConfig b
-> TableName b
-> ArrRelDef b
-> m (Maybe (RelInfo b))
buildArrayRelationship HashMap (TableName b) (HashSet (ForeignKey b))
fkeysMap SourceName
sourceName SourceConfig b
sourceConfig TableName b
table ArrRelDef b
relDef = do
  let buildRelInfo :: ArrRelDef b -> Either QErr (RelInfo b, Seq SchemaDependency)
buildRelInfo = SourceConfig b
-> SourceName
-> HashMap (TableName b) (HashSet (ForeignKey b))
-> TableName b
-> ArrRelDef b
-> Either QErr (RelInfo b, Seq SchemaDependency)
forall (b :: BackendType) (m :: * -> *).
(BackendMetadata b, MonadError QErr m) =>
SourceConfig b
-> SourceName
-> HashMap (TableName b) (HashSet (ForeignKey b))
-> TableName b
-> ArrRelDef b
-> m (RelInfo b, Seq SchemaDependency)
forall (m :: * -> *).
MonadError QErr m =>
SourceConfig b
-> SourceName
-> HashMap (TableName b) (HashSet (ForeignKey b))
-> TableName b
-> ArrRelDef b
-> m (RelInfo b, Seq SchemaDependency)
buildArrayRelationshipInfo SourceConfig b
sourceConfig SourceName
sourceName HashMap (TableName b) (HashSet (ForeignKey b))
fkeysMap TableName b
table
  SourceName
-> TableName b
-> (ArrRelDef b -> Either QErr (RelInfo b, Seq SchemaDependency))
-> RelType
-> ArrRelDef b
-> m (Maybe (RelInfo b))
forall (m :: * -> *) (b :: BackendType) a.
(MonadWriter (Seq CollectItem) m, ToJSON a, Backend b) =>
SourceName
-> TableName b
-> (RelDef a -> Either QErr (RelInfo b, Seq SchemaDependency))
-> RelType
-> RelDef a
-> m (Maybe (RelInfo b))
buildRelationship SourceName
sourceName TableName b
table ArrRelDef b -> Either QErr (RelInfo b, Seq SchemaDependency)
buildRelInfo RelType
ArrRel ArrRelDef b
relDef

buildRelationship ::
  forall m b a.
  ( MonadWriter (Seq CollectItem) m,
    ToJSON a,
    Backend b
  ) =>
  SourceName ->
  TableName b ->
  (RelDef a -> Either QErr (RelInfo b, Seq SchemaDependency)) ->
  RelType ->
  RelDef a ->
  m (Maybe (RelInfo b))
buildRelationship :: forall (m :: * -> *) (b :: BackendType) a.
(MonadWriter (Seq CollectItem) m, ToJSON a, Backend b) =>
SourceName
-> TableName b
-> (RelDef a -> Either QErr (RelInfo b, Seq SchemaDependency))
-> RelType
-> RelDef a
-> m (Maybe (RelInfo b))
buildRelationship SourceName
source TableName b
table RelDef a -> Either QErr (RelInfo b, Seq SchemaDependency)
buildRelInfo RelType
relType RelDef a
relDef = do
  let relName :: RelName
relName = RelDef a -> RelName
forall a. RelDef a -> RelName
_rdName RelDef a
relDef
      metadataObject :: MetadataObject
metadataObject = forall (b :: BackendType) a.
(ToJSON a, Backend b) =>
RelType -> SourceName -> TableName b -> RelDef a -> MetadataObject
mkRelationshipMetadataObject @b RelType
relType SourceName
source TableName b
table RelDef a
relDef
      schemaObject :: SchemaObjId
schemaObject =
        SourceName -> AnyBackend SourceObjId -> SchemaObjId
SOSourceObj SourceName
source
          (AnyBackend SourceObjId -> SchemaObjId)
-> AnyBackend SourceObjId -> SchemaObjId
forall a b. (a -> b) -> a -> b
$ SourceObjId b -> AnyBackend SourceObjId
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
AB.mkAnyBackend
          (SourceObjId b -> AnyBackend SourceObjId)
-> SourceObjId b -> AnyBackend SourceObjId
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
TableName b -> TableObjId b -> SourceObjId b
SOITableObj @b TableName b
table
          (TableObjId b -> SourceObjId b) -> TableObjId b -> SourceObjId b
forall a b. (a -> b) -> a -> b
$ RelName -> TableObjId b
forall (b :: BackendType). RelName -> TableObjId b
TORel RelName
relName
      addRelationshipContext :: Text -> Text
addRelationshipContext Text
e = Text
"in relationship " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> RelName
relName RelName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
e
  MetadataObject
-> ExceptT QErr m (RelInfo b) -> m (Maybe (RelInfo b))
forall (m :: * -> *) a.
MonadWriter (Seq CollectItem) m =>
MetadataObject -> ExceptT QErr m a -> m (Maybe a)
withRecordInconsistencyM MetadataObject
metadataObject (ExceptT QErr m (RelInfo b) -> m (Maybe (RelInfo b)))
-> ExceptT QErr m (RelInfo b) -> m (Maybe (RelInfo b))
forall a b. (a -> b) -> a -> b
$ do
    (Text -> Text)
-> ExceptT QErr m (RelInfo b) -> ExceptT QErr m (RelInfo b)
forall (m :: * -> *) a. QErrM m => (Text -> Text) -> m a -> m a
modifyErr (forall (b :: BackendType). Backend b => TableName b -> Text -> Text
addTableContext @b TableName b
table (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
addRelationshipContext) (ExceptT QErr m (RelInfo b) -> ExceptT QErr m (RelInfo b))
-> ExceptT QErr m (RelInfo b) -> ExceptT QErr m (RelInfo b)
forall a b. (a -> b) -> a -> b
$ do
      (RelInfo b
info, Seq SchemaDependency
dependencies) <- Either QErr (RelInfo b, Seq SchemaDependency)
-> ExceptT QErr m (RelInfo b, Seq SchemaDependency)
forall e (m :: * -> *) a. MonadError e m => Either e a -> m a
liftEither (Either QErr (RelInfo b, Seq SchemaDependency)
 -> ExceptT QErr m (RelInfo b, Seq SchemaDependency))
-> Either QErr (RelInfo b, Seq SchemaDependency)
-> ExceptT QErr m (RelInfo b, Seq SchemaDependency)
forall a b. (a -> b) -> a -> b
$ RelDef a -> Either QErr (RelInfo b, Seq SchemaDependency)
buildRelInfo RelDef a
relDef
      MetadataObject
-> SchemaObjId -> Seq SchemaDependency -> ExceptT QErr m ()
forall (m :: * -> *).
MonadWriter (Seq CollectItem) m =>
MetadataObject -> SchemaObjId -> Seq SchemaDependency -> m ()
recordDependenciesM MetadataObject
metadataObject SchemaObjId
schemaObject Seq SchemaDependency
dependencies
      RelInfo b -> ExceptT QErr m (RelInfo b)
forall a. a -> ExceptT QErr m a
forall (m :: * -> *) a. Monad m => a -> m a
return RelInfo b
info

mkComputedFieldMetadataObject ::
  forall b.
  (Backend b) =>
  SourceName ->
  TableName b ->
  ComputedFieldMetadata b ->
  MetadataObject
mkComputedFieldMetadataObject :: forall (b :: BackendType).
Backend b =>
SourceName
-> TableName b -> ComputedFieldMetadata b -> MetadataObject
mkComputedFieldMetadataObject SourceName
source TableName b
table ComputedFieldMetadata {Comment
ComputedFieldName
ComputedFieldDefinition b
_cfmName :: forall (b :: BackendType).
ComputedFieldMetadata b -> ComputedFieldName
_cfmName :: ComputedFieldName
_cfmDefinition :: ComputedFieldDefinition b
_cfmComment :: Comment
_cfmDefinition :: forall (b :: BackendType).
ComputedFieldMetadata b -> ComputedFieldDefinition b
_cfmComment :: forall (b :: BackendType). ComputedFieldMetadata b -> Comment
..} =
  let objectId :: MetadataObjId
objectId =
        SourceName -> AnyBackend SourceMetadataObjId -> MetadataObjId
MOSourceObjId SourceName
source
          (AnyBackend SourceMetadataObjId -> MetadataObjId)
-> AnyBackend SourceMetadataObjId -> MetadataObjId
forall a b. (a -> b) -> a -> b
$ SourceMetadataObjId b -> AnyBackend SourceMetadataObjId
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
AB.mkAnyBackend
          (SourceMetadataObjId b -> AnyBackend SourceMetadataObjId)
-> SourceMetadataObjId b -> AnyBackend SourceMetadataObjId
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
TableName b -> TableMetadataObjId -> SourceMetadataObjId b
SMOTableObj @b TableName b
table
          (TableMetadataObjId -> SourceMetadataObjId b)
-> TableMetadataObjId -> SourceMetadataObjId b
forall a b. (a -> b) -> a -> b
$ ComputedFieldName -> TableMetadataObjId
MTOComputedField ComputedFieldName
_cfmName
      definition :: AddComputedField b
definition = forall (b :: BackendType).
SourceName
-> TableName b
-> ComputedFieldName
-> ComputedFieldDefinition b
-> Comment
-> AddComputedField b
AddComputedField @b SourceName
source TableName b
table ComputedFieldName
_cfmName ComputedFieldDefinition b
_cfmDefinition Comment
_cfmComment
   in MetadataObjId -> Value -> MetadataObject
MetadataObject MetadataObjId
objectId (AddComputedField b -> Value
forall a. ToJSON a => a -> Value
toJSON AddComputedField b
definition)

buildComputedField ::
  forall b m.
  ( MonadWriter (Seq CollectItem) m,
    BackendMetadata b
  ) =>
  HashSet (TableName b) ->
  HashSet (Column b) ->
  SourceName ->
  DBFunctionsMetadata b ->
  TableName b ->
  ComputedFieldMetadata b ->
  m (Maybe (ComputedFieldInfo b))
buildComputedField :: forall (b :: BackendType) (m :: * -> *).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashSet (TableName b)
-> HashSet (Column b)
-> SourceName
-> DBFunctionsMetadata b
-> TableName b
-> ComputedFieldMetadata b
-> m (Maybe (ComputedFieldInfo b))
buildComputedField HashSet (TableName b)
trackedTableNames HashSet (Column b)
tableColumns SourceName
source DBFunctionsMetadata b
pgFunctions TableName b
table cf :: ComputedFieldMetadata b
cf@ComputedFieldMetadata {Comment
ComputedFieldName
ComputedFieldDefinition b
_cfmName :: forall (b :: BackendType).
ComputedFieldMetadata b -> ComputedFieldName
_cfmDefinition :: forall (b :: BackendType).
ComputedFieldMetadata b -> ComputedFieldDefinition b
_cfmComment :: forall (b :: BackendType). ComputedFieldMetadata b -> Comment
_cfmName :: ComputedFieldName
_cfmDefinition :: ComputedFieldDefinition b
_cfmComment :: Comment
..} = do
  let addComputedFieldContext :: Text -> Text
addComputedFieldContext Text
e = Text
"in computed field " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ComputedFieldName
_cfmName ComputedFieldName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
e
      function :: FunctionName b
function = forall (b :: BackendType).
Backend b =>
ComputedFieldDefinition b -> FunctionName b
computedFieldFunction @b ComputedFieldDefinition b
_cfmDefinition

  MetadataObject
-> ExceptT QErr m (ComputedFieldInfo b)
-> m (Maybe (ComputedFieldInfo b))
forall (m :: * -> *) a.
MonadWriter (Seq CollectItem) m =>
MetadataObject -> ExceptT QErr m a -> m (Maybe a)
withRecordInconsistencyM (SourceName
-> TableName b -> ComputedFieldMetadata b -> MetadataObject
forall (b :: BackendType).
Backend b =>
SourceName
-> TableName b -> ComputedFieldMetadata b -> MetadataObject
mkComputedFieldMetadataObject SourceName
source TableName b
table ComputedFieldMetadata b
cf)
    (ExceptT QErr m (ComputedFieldInfo b)
 -> m (Maybe (ComputedFieldInfo b)))
-> ExceptT QErr m (ComputedFieldInfo b)
-> m (Maybe (ComputedFieldInfo b))
forall a b. (a -> b) -> a -> b
$ (Text -> Text)
-> ExceptT QErr m (ComputedFieldInfo b)
-> ExceptT QErr m (ComputedFieldInfo b)
forall (m :: * -> *) a. QErrM m => (Text -> Text) -> m a -> m a
modifyErr (forall (b :: BackendType). Backend b => TableName b -> Text -> Text
addTableContext @b TableName b
table (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
addComputedFieldContext)
    (ExceptT QErr m (ComputedFieldInfo b)
 -> ExceptT QErr m (ComputedFieldInfo b))
-> ExceptT QErr m (ComputedFieldInfo b)
-> ExceptT QErr m (ComputedFieldInfo b)
forall a b. (a -> b) -> a -> b
$ do
      FunctionOverloads b
funcDefs <-
        Maybe (FunctionOverloads b)
-> ExceptT QErr m (FunctionOverloads b)
-> ExceptT QErr m (FunctionOverloads b)
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing
          (FunctionName b
-> DBFunctionsMetadata b -> Maybe (FunctionOverloads b)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup FunctionName b
function DBFunctionsMetadata b
pgFunctions)
          (Code -> Text -> ExceptT QErr m (FunctionOverloads b)
forall (m :: * -> *) a. QErrM m => Code -> Text -> m a
throw400 Code
NotExists (Text -> ExceptT QErr m (FunctionOverloads b))
-> Text -> ExceptT QErr m (FunctionOverloads b)
forall a b. (a -> b) -> a -> b
$ Text
"no such function exists: " Text -> FunctionName b -> Text
forall t. ToTxt t => Text -> t -> Text
<>> FunctionName b
function)
      RawFunctionInfo b
rawfi <- forall (b :: BackendType) (m :: * -> *).
(QErrM m, Backend b) =>
FunctionName b -> FunctionOverloads b -> m (RawFunctionInfo b)
getSingleUniqueFunctionOverload @b (forall (b :: BackendType).
Backend b =>
ComputedFieldDefinition b -> FunctionName b
computedFieldFunction @b ComputedFieldDefinition b
_cfmDefinition) FunctionOverloads b
funcDefs
      HashSet (TableName b)
-> TableName b
-> HashSet (Column b)
-> ComputedFieldName
-> ComputedFieldDefinition b
-> RawFunctionInfo b
-> Comment
-> ExceptT QErr m (ComputedFieldInfo b)
forall (b :: BackendType) (m :: * -> *).
(BackendMetadata b, MonadError QErr m) =>
HashSet (TableName b)
-> TableName b
-> HashSet (Column b)
-> ComputedFieldName
-> ComputedFieldDefinition b
-> RawFunctionInfo b
-> Comment
-> m (ComputedFieldInfo b)
forall (m :: * -> *).
MonadError QErr m =>
HashSet (TableName b)
-> TableName b
-> HashSet (Column b)
-> ComputedFieldName
-> ComputedFieldDefinition b
-> RawFunctionInfo b
-> Comment
-> m (ComputedFieldInfo b)
buildComputedFieldInfo HashSet (TableName b)
trackedTableNames TableName b
table HashSet (Column b)
tableColumns ComputedFieldName
_cfmName ComputedFieldDefinition b
_cfmDefinition RawFunctionInfo b
rawfi Comment
_cfmComment

mkRemoteRelationshipMetadataObject ::
  forall b.
  (Backend b) =>
  SourceName ->
  TableName b ->
  RemoteRelationship ->
  MetadataObject
mkRemoteRelationshipMetadataObject :: forall (b :: BackendType).
Backend b =>
SourceName -> TableName b -> RemoteRelationship -> MetadataObject
mkRemoteRelationshipMetadataObject SourceName
source TableName b
table RemoteRelationship {RelName
RemoteRelationshipDefinition
_rrName :: forall definition. RemoteRelationshipG definition -> RelName
_rrName :: RelName
_rrDefinition :: RemoteRelationshipDefinition
_rrDefinition :: forall definition. RemoteRelationshipG definition -> definition
..} =
  let objectId :: MetadataObjId
objectId =
        SourceName -> AnyBackend SourceMetadataObjId -> MetadataObjId
MOSourceObjId SourceName
source
          (AnyBackend SourceMetadataObjId -> MetadataObjId)
-> AnyBackend SourceMetadataObjId -> MetadataObjId
forall a b. (a -> b) -> a -> b
$ SourceMetadataObjId b -> AnyBackend SourceMetadataObjId
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
AB.mkAnyBackend
          (SourceMetadataObjId b -> AnyBackend SourceMetadataObjId)
-> SourceMetadataObjId b -> AnyBackend SourceMetadataObjId
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
TableName b -> TableMetadataObjId -> SourceMetadataObjId b
SMOTableObj @b TableName b
table
          (TableMetadataObjId -> SourceMetadataObjId b)
-> TableMetadataObjId -> SourceMetadataObjId b
forall a b. (a -> b) -> a -> b
$ RelName -> TableMetadataObjId
MTORemoteRelationship RelName
_rrName
   in MetadataObjId -> Value -> MetadataObject
MetadataObject MetadataObjId
objectId
        (Value -> MetadataObject) -> Value -> MetadataObject
forall a b. (a -> b) -> a -> b
$ CreateFromSourceRelationship b -> Value
forall a. ToJSON a => a -> Value
toJSON
        (CreateFromSourceRelationship b -> Value)
-> CreateFromSourceRelationship b -> Value
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
SourceName
-> TableName b
-> RelName
-> RemoteRelationshipDefinition
-> CreateFromSourceRelationship b
CreateFromSourceRelationship @b SourceName
source TableName b
table RelName
_rrName RemoteRelationshipDefinition
_rrDefinition

--  | This is a "thin" wrapper around 'buildRemoteFieldInfo', which only knows
-- how to construct dependencies on the RHS of the join condition, so the
-- dependencies on the remote relationship on the LHS entity are computed here
buildRemoteRelationship ::
  forall b m.
  ( MonadWriter (Seq CollectItem) m,
    BackendMetadata b
  ) =>
  HashMap SourceName (AB.AnyBackend PartiallyResolvedSource) ->
  HashMap.HashMap FieldName (DBJoinField b) ->
  PartiallyResolvedRemoteSchemaMap ->
  SourceName ->
  TableName b ->
  RemoteRelationship ->
  m (Maybe (RemoteFieldInfo (DBJoinField b)))
buildRemoteRelationship :: forall (b :: BackendType) (m :: * -> *).
(MonadWriter (Seq CollectItem) m, BackendMetadata b) =>
HashMap SourceName (AnyBackend PartiallyResolvedSource)
-> HashMap FieldName (DBJoinField b)
-> PartiallyResolvedRemoteSchemaMap
-> SourceName
-> TableName b
-> RemoteRelationship
-> m (Maybe (RemoteFieldInfo (DBJoinField b)))
buildRemoteRelationship HashMap SourceName (AnyBackend PartiallyResolvedSource)
allSources HashMap FieldName (DBJoinField b)
allColumns PartiallyResolvedRemoteSchemaMap
remoteSchemaMap SourceName
source TableName b
table rr :: RemoteRelationship
rr@RemoteRelationship {RelName
RemoteRelationshipDefinition
_rrName :: forall definition. RemoteRelationshipG definition -> RelName
_rrDefinition :: forall definition. RemoteRelationshipG definition -> definition
_rrName :: RelName
_rrDefinition :: RemoteRelationshipDefinition
..} = do
  let metadataObject :: MetadataObject
metadataObject = forall (b :: BackendType).
Backend b =>
SourceName -> TableName b -> RemoteRelationship -> MetadataObject
mkRemoteRelationshipMetadataObject @b SourceName
source TableName b
table RemoteRelationship
rr
      schemaObj :: SchemaObjId
schemaObj =
        SourceName -> AnyBackend SourceObjId -> SchemaObjId
SOSourceObj SourceName
source
          (AnyBackend SourceObjId -> SchemaObjId)
-> AnyBackend SourceObjId -> SchemaObjId
forall a b. (a -> b) -> a -> b
$ SourceObjId b -> AnyBackend SourceObjId
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
AB.mkAnyBackend
          (SourceObjId b -> AnyBackend SourceObjId)
-> SourceObjId b -> AnyBackend SourceObjId
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
TableName b -> TableObjId b -> SourceObjId b
SOITableObj @b TableName b
table
          (TableObjId b -> SourceObjId b) -> TableObjId b -> SourceObjId b
forall a b. (a -> b) -> a -> b
$ RelName -> TableObjId b
forall (b :: BackendType). RelName -> TableObjId b
TORemoteRel RelName
_rrName
      addRemoteRelationshipContext :: Text -> Text
addRemoteRelationshipContext Text
e = Text
"in remote relationship " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> RelName
_rrName RelName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
e
  MetadataObject
-> ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
-> m (Maybe (RemoteFieldInfo (DBJoinField b)))
forall (m :: * -> *) a.
MonadWriter (Seq CollectItem) m =>
MetadataObject -> ExceptT QErr m a -> m (Maybe a)
withRecordInconsistencyM MetadataObject
metadataObject
    (ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
 -> m (Maybe (RemoteFieldInfo (DBJoinField b))))
-> ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
-> m (Maybe (RemoteFieldInfo (DBJoinField b)))
forall a b. (a -> b) -> a -> b
$ (Text -> Text)
-> ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
-> ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
forall (m :: * -> *) a. QErrM m => (Text -> Text) -> m a -> m a
modifyErr (forall (b :: BackendType). Backend b => TableName b -> Text -> Text
addTableContext @b TableName b
table (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
addRemoteRelationshipContext)
    (ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
 -> ExceptT QErr m (RemoteFieldInfo (DBJoinField b)))
-> ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
-> ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
forall a b. (a -> b) -> a -> b
$ do
      (RemoteFieldInfo (DBJoinField b)
remoteField, Seq SchemaDependency
rhsDependencies) <-
        LHSIdentifier
-> HashMap FieldName (DBJoinField b)
-> RemoteRelationship
-> HashMap SourceName (AnyBackend PartiallyResolvedSource)
-> PartiallyResolvedRemoteSchemaMap
-> ExceptT
     QErr m (RemoteFieldInfo (DBJoinField b), Seq SchemaDependency)
forall (m :: * -> *) lhsJoinField.
QErrM m =>
LHSIdentifier
-> HashMap FieldName lhsJoinField
-> RemoteRelationship
-> HashMap SourceName (AnyBackend PartiallyResolvedSource)
-> PartiallyResolvedRemoteSchemaMap
-> m (RemoteFieldInfo lhsJoinField, Seq SchemaDependency)
buildRemoteFieldInfo (forall (b :: BackendType).
Backend b =>
TableName b -> LHSIdentifier
tableNameToLHSIdentifier @b TableName b
table) HashMap FieldName (DBJoinField b)
allColumns RemoteRelationship
rr HashMap SourceName (AnyBackend PartiallyResolvedSource)
allSources PartiallyResolvedRemoteSchemaMap
remoteSchemaMap
      let lhsDependencies :: [SchemaDependency]
lhsDependencies =
            -- a direct dependency on the table on which this is defined
            SchemaObjId -> DependencyReason -> SchemaDependency
SchemaDependency (SourceName -> AnyBackend SourceObjId -> SchemaObjId
SOSourceObj SourceName
source (AnyBackend SourceObjId -> SchemaObjId)
-> AnyBackend SourceObjId -> SchemaObjId
forall a b. (a -> b) -> a -> b
$ SourceObjId b -> AnyBackend SourceObjId
forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
i b -> AnyBackend i
AB.mkAnyBackend (SourceObjId b -> AnyBackend SourceObjId)
-> SourceObjId b -> AnyBackend SourceObjId
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType). TableName b -> SourceObjId b
SOITable @b TableName b
table) DependencyReason
DRTable
              -- the relationship is also dependent on all the lhs
              -- columns that are used in the join condition
              SchemaDependency -> [SchemaDependency] -> [SchemaDependency]
forall a. a -> [a] -> [a]
: ((DBJoinField b -> SchemaDependency)
 -> [DBJoinField b] -> [SchemaDependency])
-> [DBJoinField b]
-> (DBJoinField b -> SchemaDependency)
-> [SchemaDependency]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (DBJoinField b -> SchemaDependency)
-> [DBJoinField b] -> [SchemaDependency]
forall a b. (a -> b) -> [a] -> [b]
map (HashMap FieldName (DBJoinField b) -> [DBJoinField b]
forall k v. HashMap k v -> [v]
HashMap.elems (HashMap FieldName (DBJoinField b) -> [DBJoinField b])
-> HashMap FieldName (DBJoinField b) -> [DBJoinField b]
forall a b. (a -> b) -> a -> b
$ RemoteFieldInfo (DBJoinField b)
-> HashMap FieldName (DBJoinField b)
forall lhsJoinField.
RemoteFieldInfo lhsJoinField -> HashMap FieldName lhsJoinField
_rfiLHS RemoteFieldInfo (DBJoinField b)
remoteField) \case
                JoinColumn Column b
column ColumnType b
_ ->
                  -- TODO: shouldn't this be DRColumn??
                  forall (b :: BackendType).
Backend b =>
DependencyReason
-> SourceName -> TableName b -> Column b -> SchemaDependency
mkColDep @b DependencyReason
DRRemoteRelationship SourceName
source TableName b
table Column b
column
                JoinComputedField ScalarComputedField b
computedFieldInfo ->
                  forall (b :: BackendType).
Backend b =>
DependencyReason
-> SourceName
-> TableName b
-> ComputedFieldName
-> SchemaDependency
mkComputedFieldDep @b DependencyReason
DRRemoteRelationship SourceName
source TableName b
table (ComputedFieldName -> SchemaDependency)
-> ComputedFieldName -> SchemaDependency
forall a b. (a -> b) -> a -> b
$ ScalarComputedField b -> ComputedFieldName
forall (b :: BackendType).
ScalarComputedField b -> ComputedFieldName
_scfName ScalarComputedField b
computedFieldInfo
      -- Here is the essence of the function: construct dependencies on the RHS
      -- of the join condition.
      MetadataObject
-> SchemaObjId -> Seq SchemaDependency -> ExceptT QErr m ()
forall (m :: * -> *).
MonadWriter (Seq CollectItem) m =>
MetadataObject -> SchemaObjId -> Seq SchemaDependency -> m ()
recordDependenciesM MetadataObject
metadataObject SchemaObjId
schemaObj ([SchemaDependency] -> Seq SchemaDependency
forall a. [a] -> Seq a
Seq.fromList [SchemaDependency]
lhsDependencies Seq SchemaDependency
-> Seq SchemaDependency -> Seq SchemaDependency
forall a. Semigroup a => a -> a -> a
<> Seq SchemaDependency
rhsDependencies)
      RemoteFieldInfo (DBJoinField b)
-> ExceptT QErr m (RemoteFieldInfo (DBJoinField b))
forall a. a -> ExceptT QErr m a
forall (m :: * -> *) a. Monad m => a -> m a
return RemoteFieldInfo (DBJoinField b)
remoteField