content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  module Glean.Glass.Digest
    (
      fetchFileDigests,
      toDigest,
      toDigestMap
    ) where
  
  import Data.Text ( Text )
  import Data.Map.Strict ( Map )
  import qualified Data.Map.Strict as Map
  
  import qualified Glean
  import Glean.Haxl.Repos as Glean
  import qualified Glean.Glass.Query as Query
  import Glean.Glass.Utils ( searchWithLimit )
  
  import Glean.Glass.Types
  
  import qualified Glean.Schema.Digest.Types as Digest
  import qualified Glean.Schema.Src.Types as Src
  
  type RepoName_ = Text -- avoid newtype double-quoting in thrift
  
  fetchFileDigests
    :: Int -> [Glean.IdOf Src.File] -> Glean.RepoHaxl u w [Digest.FileDigest]
  fetchFileDigests _ [] = pure [] -- avoid an empty call
  fetchFileDigests n srcFiles = searchWithLimit (Just n) query
    where
      query = Query.fileDigests srcFiles
  
  -- Export Src.Digest to Glass type
  toDigest :: Digest.Digest -> FileDigest
  toDigest Digest.Digest{..} = FileDigest{..}
    where
      fileDigest_hash = digest_hash
      fileDigest_size = Glean.unNat digest_size
  
  -- Join the fileDigest predicate (keyed by id) back onto the full repo/path
  toDigestMap
    :: Map (Glean.IdOf Src.File) (RepoName, Path)
    -> [Digest.FileDigest]
    -> Glean.RepoHaxl u w (Map RepoName_ FileDigestMap)
  toDigestMap fileIdMap digests = go digests mempty
    where
      go [] !acc = pure acc
      go (pred:ps) !acc = do
        Digest.FileDigest_key fileId digest <- Glean.keyOf pred
        case Map.lookup (Glean.getId fileId) fileIdMap of
          Nothing -> go ps acc -- digest with no associated file
          Just (RepoName repo, Path path) -> do
            let v = Map.singleton path (toDigest digest)
            go ps $! Map.insertWith mappend repo v acc
  