grapesy-1.0.0: kvstore/KVStore/API/JSON.hs
{-# OPTIONS_GHC -Wno-orphans #-}
module KVStore.API.JSON (client, server) where
import Network.GRPC.Client (rpc)
import Network.GRPC.Client qualified as Client
import Network.GRPC.Client.StreamType.IO qualified as Client
import Network.GRPC.Common
import Network.GRPC.Common.JSON
import Network.GRPC.Server qualified as Server
import Network.GRPC.Server.StreamType qualified as Server
import KVStore.API
import KVStore.Util.Profiling
{-------------------------------------------------------------------------------
API
-------------------------------------------------------------------------------}
type KeyValueService = "io.grpc.KeyValueService"
type Create = JsonRpc KeyValueService "Create"
type Delete = JsonRpc KeyValueService "Delete"
type Retrieve = JsonRpc KeyValueService "Retrieve"
type Update = JsonRpc KeyValueService "Update"
type instance Input Create = JsonObject '[ '("key", Required Key), '("value", Required Value) ]
type instance Output Create = JsonObject '[ ]
type instance Input Retrieve = JsonObject '[ '("key", Required Key) ]
type instance Output Retrieve = JsonObject '[ '("value", Required Value) ]
type instance Input Update = JsonObject '[ '("key", Required Key), '("value", Required Value) ]
type instance Output Update = JsonObject '[ ]
type instance Input Delete = JsonObject '[ '("key", Required Key) ]
type instance Output Delete = JsonObject '[ ]
{-------------------------------------------------------------------------------
Metadata
-------------------------------------------------------------------------------}
type instance RequestMetadata (JsonRpc KeyValueService meth) = NoMetadata
type instance ResponseInitialMetadata (JsonRpc KeyValueService meth) = NoMetadata
type instance ResponseTrailingMetadata (JsonRpc KeyValueService meth) = NoMetadata
{-------------------------------------------------------------------------------
Client
-------------------------------------------------------------------------------}
client :: Client.Connection -> KVStore
client conn = KVStore {
create = fmap to0 . Client.nonStreaming conn (rpc @Create) . from2
, delete = fmap to0 . Client.nonStreaming conn (rpc @Delete) . from1
, retrieve = fmap to1 . Client.nonStreaming conn (rpc @Retrieve) . from1
, update = fmap to0 . Client.nonStreaming conn (rpc @Update) . from2
}
{-------------------------------------------------------------------------------
Server
Unlike in the Protobuf case, we don't have a type-level description of the
full API here.
-------------------------------------------------------------------------------}
server :: KVStore -> [Server.SomeRpcHandler IO]
server kvstore = [
Server.fromMethod @Create $ markNonStreaming "create" $ fmap from0 . create kvstore . to2
, Server.fromMethod @Delete $ markNonStreaming "delete" $ fmap from0 . delete kvstore . to1
, Server.fromMethod @Retrieve $ markNonStreaming "retrieve" $ fmap from1 . retrieve kvstore . to1
, Server.fromMethod @Update $ markNonStreaming "update" $ fmap from0 . update kvstore . to2
]
{-------------------------------------------------------------------------------
Marshalling
-------------------------------------------------------------------------------}
to0 :: JsonObject '[] -> ()
to0 JsonObject = ()
from0 :: () -> JsonObject '[]
from0 () = JsonObject
to1 :: JsonObject '[ '(a, Required x) ] -> x
to1 (Required x :* JsonObject) = x
from1 :: x -> JsonObject '[ '(a, Required x) ]
from1 x = Required x :* JsonObject
to2 :: JsonObject '[ '(a, Required x), '(b, Required y) ] -> (x, y)
to2 (Required key :* Required value :* JsonObject) = (key, value)
from2 :: (x, y) -> JsonObject '[ '(a, Required x), '(b, Required y) ]
from2 (key, value) = Required key :* Required value :* JsonObject