-- | Common codecs shared between similar logical model resolvers.
module Hasura.LogicalModelResolver.Codec
  ( nativeQueryRelationshipsCodec,
  )
where

import Autodocodec (HasCodec (), HasObjectCodec (..), bimapCodec)
import Autodocodec qualified as AC
import Data.Aeson (Value)
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
import Hasura.Prelude hiding (first)
import Hasura.RQL.Types.Backend (Backend (..))
import Hasura.RQL.Types.Common (RelName)
import Hasura.RQL.Types.Relationships.Local (RelDef, RelManualNativeQueryConfig)

-- | Codec for native-query-only relationships
nativeQueryRelationshipsCodec ::
  forall b.
  (Backend b) =>
  AC.Codec
    Value
    (InsOrdHashMap.InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
    (InsOrdHashMap.InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
nativeQueryRelationshipsCodec :: forall (b :: BackendType).
Backend b =>
Codec
  Value
  (InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
  (InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
nativeQueryRelationshipsCodec =
  ([MergedObject
    (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
 -> InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
-> (InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b))
    -> [MergedObject
          (NameField RelName) (RelDef (RelManualNativeQueryConfig b))])
-> Codec
     Value
     [MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
     [MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
-> Codec
     Value
     (InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
     (InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
forall oldOutput newOutput newInput oldInput context.
(oldOutput -> newOutput)
-> (newInput -> oldInput)
-> Codec context oldInput oldOutput
-> Codec context newInput newOutput
AC.dimapCodec
    ( [(RelName, RelDef (RelManualNativeQueryConfig b))]
-> InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b))
forall k v. (Eq k, Hashable k) => [(k, v)] -> InsOrdHashMap k v
InsOrdHashMap.fromList
        ([(RelName, RelDef (RelManualNativeQueryConfig b))]
 -> InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b)))
-> ([MergedObject
       (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
    -> [(RelName, RelDef (RelManualNativeQueryConfig b))])
-> [MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
-> InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MergedObject
   (NameField RelName) (RelDef (RelManualNativeQueryConfig b))
 -> (RelName, RelDef (RelManualNativeQueryConfig b)))
-> [MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
-> [(RelName, RelDef (RelManualNativeQueryConfig b))]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
          ( \(MergedObject (NameField RelName
name) RelDef (RelManualNativeQueryConfig b)
nst) ->
              (RelName
name, RelDef (RelManualNativeQueryConfig b)
nst)
          )
    )
    ( ((RelName, RelDef (RelManualNativeQueryConfig b))
 -> MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
-> [(RelName, RelDef (RelManualNativeQueryConfig b))]
-> [MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(RelName
fld, RelDef (RelManualNativeQueryConfig b)
nst) -> NameField RelName
-> RelDef (RelManualNativeQueryConfig b)
-> MergedObject
     (NameField RelName) (RelDef (RelManualNativeQueryConfig b))
forall a b. a -> b -> MergedObject a b
MergedObject (RelName -> NameField RelName
forall a. a -> NameField a
NameField RelName
fld) RelDef (RelManualNativeQueryConfig b)
nst) ([(RelName, RelDef (RelManualNativeQueryConfig b))]
 -> [MergedObject
       (NameField RelName) (RelDef (RelManualNativeQueryConfig b))])
-> (InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b))
    -> [(RelName, RelDef (RelManualNativeQueryConfig b))])
-> InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b))
-> [MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InsOrdHashMap RelName (RelDef (RelManualNativeQueryConfig b))
-> [(RelName, RelDef (RelManualNativeQueryConfig b))]
forall k v. InsOrdHashMap k v -> [(k, v)]
InsOrdHashMap.toList
    )
    ( ValueCodec
  (MergedObject
     (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
  (MergedObject
     (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
-> Codec
     Value
     [MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
     [MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
forall input output.
ValueCodec input output -> ValueCodec [input] [output]
AC.listCodec
        (ValueCodec
   (MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
   (MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
 -> Codec
      Value
      [MergedObject
         (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
      [MergedObject
         (NameField RelName) (RelDef (RelManualNativeQueryConfig b))])
-> ValueCodec
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
-> Codec
     Value
     [MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
     [MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b))]
forall a b. (a -> b) -> a -> b
$ Text
-> ObjectCodec
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
-> ValueCodec
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
forall input output.
Text -> ObjectCodec input output -> ValueCodec input output
AC.object Text
"RelDefRelManualNativeQueryConfig"
        (ObjectCodec
   (MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
   (MergedObject
      (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
 -> ValueCodec
      (MergedObject
         (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
      (MergedObject
         (NameField RelName) (RelDef (RelManualNativeQueryConfig b))))
-> ObjectCodec
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
-> ValueCodec
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
     (MergedObject
        (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
forall a b. (a -> b) -> a -> b
$ forall object. HasObjectCodec object => JSONObjectCodec object
AC.objectCodec @(MergedObject (NameField RelName) (RelDef (RelManualNativeQueryConfig b)))
    )

data MergedObject a b = MergedObject
  { forall a b. MergedObject a b -> a
moFst :: a,
    forall a b. MergedObject a b -> b
moSnd :: b
  }

instance (HasObjectCodec a, HasObjectCodec b) => HasObjectCodec (MergedObject a b) where
  objectCodec :: JSONObjectCodec (MergedObject a b)
objectCodec = a -> b -> MergedObject a b
forall a b. a -> b -> MergedObject a b
MergedObject (a -> b -> MergedObject a b)
-> Codec Object (MergedObject a b) a
-> Codec Object (MergedObject a b) (b -> MergedObject a b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (a -> Either String a)
-> (MergedObject a b -> a)
-> Codec Object a a
-> Codec Object (MergedObject a b) a
forall oldOutput newOutput newInput oldInput context.
(oldOutput -> Either String newOutput)
-> (newInput -> oldInput)
-> Codec context oldInput oldOutput
-> Codec context newInput newOutput
bimapCodec a -> Either String a
forall a b. b -> Either a b
Right MergedObject a b -> a
forall a b. MergedObject a b -> a
moFst Codec Object a a
forall object. HasObjectCodec object => JSONObjectCodec object
objectCodec Codec Object (MergedObject a b) (b -> MergedObject a b)
-> Codec Object (MergedObject a b) b
-> JSONObjectCodec (MergedObject a b)
forall a b.
Codec Object (MergedObject a b) (a -> b)
-> Codec Object (MergedObject a b) a
-> Codec Object (MergedObject a b) b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (b -> Either String b)
-> (MergedObject a b -> b)
-> Codec Object b b
-> Codec Object (MergedObject a b) b
forall oldOutput newOutput newInput oldInput context.
(oldOutput -> Either String newOutput)
-> (newInput -> oldInput)
-> Codec context oldInput oldOutput
-> Codec context newInput newOutput
bimapCodec b -> Either String b
forall a b. b -> Either a b
Right MergedObject a b -> b
forall a b. MergedObject a b -> b
moSnd Codec Object b b
forall object. HasObjectCodec object => JSONObjectCodec object
objectCodec

newtype NameField a = NameField {forall a. NameField a -> a
nameField :: a}

instance (HasCodec a) => HasObjectCodec (NameField a) where
  objectCodec :: JSONObjectCodec (NameField a)
objectCodec = a -> NameField a
forall a. a -> NameField a
NameField (a -> NameField a)
-> Codec Object (NameField a) a -> JSONObjectCodec (NameField a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Text -> ObjectCodec a a
forall output.
HasCodec output =>
Text -> Text -> ObjectCodec output output
AC.requiredField Text
"name" Text
"name" ObjectCodec a a
-> (NameField a -> a) -> Codec Object (NameField a) a
forall oldInput output newInput.
ObjectCodec oldInput output
-> (newInput -> oldInput) -> ObjectCodec newInput output
AC..= NameField a -> a
forall a. NameField a -> a
nameField