Repository: hasura/graphql-engine
File: server/src-lib/Hasura/RQL/DDL/Metadata.hs (Haskell)

Code before:
     , MonadIO m
     , MonadTx m
     , CacheRWM m
     , HasSystemDefined m
     , HasHttpManager m
     )
  => ReplaceMetadata
  -> m EncJSON
applyQP2 (ReplaceMetadata _ tables functionsMeta
          schemas collections allowlist customTypes actions) = do

  liftTx clearMetadata
  buildSchemaCacheStrict

  withPathK "tables" $ do
    -- tables and views
    
    -- NOTE: this is essentially a more efficient bulk 'Schema.trackExistingTableOrViewP2':
    withBuildSchemaCache $ do
      typeMap <- GC._gTypes . scDefaultRemoteGCtx <$> askSchemaCache
      indexedForM tables $ \TableMeta{..} -> do
        -- It should be okay to do this check against old cache as we work through new tables; we've 
        -- already checked for duplicates in the track table payload:
        GS.checkConflictingNode typeMap $ GS.qualObjectToName _tmTable
        saveTableToCatalog _tmTable _tmIsEnum _tmConfiguration
        return (MOTable _tmTable)

    indexedForM_ tables $ \table -> do
      -- Relationships
      withPathK "object_relationships" $
        indexedForM_ (table ^. tmObjectRelationships) $ \objRel ->
        Relationship.insertRelationshipToCatalog (table ^. tmTable) ObjRel objRel
      withPathK "array_relationships" $
        indexedForM_ (table ^. tmArrayRelationships) $ \arrRel ->
        Relationship.insertRelationshipToCatalog (table ^. tmTable) ArrRel arrRel
      -- Computed Fields
      withPathK "computed_fields" $
        indexedForM_ (table ^. tmComputedFields) $
          \(ComputedFieldMeta name definition comment) ->
            ComputedField.addComputedFieldToCatalog $
              ComputedField.AddComputedField (table ^. tmTable) name definition comment

    -- Permissions
    indexedForM_ tables $ \table -> do
      let tableName = table ^. tmTable
      tabInfo <- modifyErrAndSet500 ("apply " <> ) $ askTableCoreInfo tableName
      withPathK "insert_permissions" $ processPerms tabInfo $
        table ^. tmInsertPermissions
      withPathK "select_permissions" $ processPerms tabInfo $
        table ^. tmSelectPermissions
      withPathK "update_permissions" $ processPerms tabInfo $

Review comment (performance):
I think we don't need to build schema cache here and check for inconsistent tables/views. Ideally in replace metadata, we should be _only saving the metadata in the catalog_ and do `buildSchemaCacheStrict` at the end. 

Define a new function with name like `saveMetadata` with definition as follows
```haskell
saveMetadata :: (MonadTx m, HasSystemDefined m) => ReplaceMetadata -> m ()
```
It should only insert the metadata items in the catalog. Move the code from `withPathK "tables"` to `forM_ actions .. ` snippet to this function. Also, we should be only using `addRemoteSchemaToCatalog` instead of `addRemoteSchemaP2` for remote schemas. Eventually, `applyQP2` function will look like

```haskell
applyQP2 replaceMetadata = do
  liftTx clearMetadata
  saveMetadata replaceMetadata
  buildSchemaCacheStrict
  pure successMsg
```

Code after:
  buildSchemaCacheStrict
  pure successMsg

saveMetadata :: (MonadTx m, HasSystemDefined m) => ReplaceMetadata -> m ()
saveMetadata (ReplaceMetadata _ tables functionsMeta
              schemas collections allowlist customTypes actions) = do

  withPathK "tables" $ do
    indexedForM_ tables $ \TableMeta{..} -> do
      -- Save table
      saveTableToCatalog _tmTable _tmIsEnum _tmConfiguration

      -- Relationships
      withPathK "object_relationships" $
        indexedForM_ _tmObjectRelationships $ \objRel ->
        Relationship.insertRelationshipToCatalog _tmTable ObjRel objRel
      withPathK "array_relationships" $
        indexedForM_ _tmArrayRelationships $ \arrRel ->
        Relationship.insertRelationshipToCatalog _tmTable ArrRel arrRel

      -- Computed Fields
      withPathK "computed_fields" $
        indexedForM_ _tmComputedFields $
          \(ComputedFieldMeta name definition comment) ->
            ComputedField.addComputedFieldToCatalog $
              ComputedField.AddComputedField _tmTable name definition comment

      -- Permissions
      withPathK "insert_permissions" $ processPerms _tmTable _tmInsertPermissions
      withPathK "select_permissions" $ processPerms _tmTable _tmSelectPermissions
      withPathK "update_permissions" $ processPerms _tmTable _tmUpdatePermissions
      withPathK "delete_permissions" $ processPerms _tmTable _tmDeletePermissions

      -- Event triggers
      withPathK "event_triggers" $
        indexedForM_ _tmEventTriggers $ \etc -> subTableP2 _tmTable False etc

  -- sql functions
  withPathK "functions" $ case functionsMeta of
    FMVersion1 qualifiedFunctions -> indexedForM_ qualifiedFunctions $
      \qf -> Schema.saveFunctionToCatalog qf Schema.emptyFunctionConfig
    FMVersion2 functionsV2 -> indexedForM_ functionsV2 $
      \(Schema.TrackFunctionV2 function config) -> Schema.saveFunctionToCatalog function config

  -- query collections
  systemDefined <- askSystemDefined
  withPathK "query_collections" $
    indexedForM_ collections $ \c -> liftTx $ Collection.addCollectionToCatalog c systemDefined

  -- allow list
  withPathK "allowlist" $ do