module Hasura.GraphQL.Schema.Node
(
NodeId (..),
V1NodeId (..),
V2NodeId (..),
NodeIdVersion,
nodeIdVersionInt,
currentNodeIdVersion,
NodeMap,
TableMap (..),
NodeInfo (..),
findNode,
)
where
import Data.Aeson qualified as J
import Data.Aeson.Types qualified as J
import Data.HashMap.Strict qualified as HashMap
import Data.Sequence qualified as Seq
import Data.Sequence.NonEmpty qualified as NESeq
import Hasura.Backends.Postgres.SQL.Types qualified as Postgres
import Hasura.Prelude
import Hasura.RQL.IR qualified as IR
import Hasura.RQL.Types.Backend
import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.Source
import Hasura.SQL.AnyBackend qualified as AB
import Hasura.Table.Cache
data NodeId
= NodeIdV1 V1NodeId
| NodeIdV2 (AB.AnyBackend V2NodeId)
data V1NodeId = V1NodeId
{ V1NodeId -> QualifiedTable
_ni1Table :: Postgres.QualifiedTable,
V1NodeId -> NESeq Value
_ni1Columns :: NESeq.NESeq J.Value
}
data V2NodeId b = V2NodeId
{ forall (b :: BackendType). V2NodeId b -> SourceName
_ni2Source :: SourceName,
forall (b :: BackendType). V2NodeId b -> TableName b
_ni2Table :: TableName b,
forall (b :: BackendType). V2NodeId b -> NESeq Value
_ni2Columns :: NESeq.NESeq J.Value
}
instance J.FromJSON NodeId where
parseJSON :: Value -> Parser NodeId
parseJSON = String -> (Array -> Parser NodeId) -> Value -> Parser NodeId
forall a. String -> (Array -> Parser a) -> Value -> Parser a
J.withArray String
"node id" \Array
array -> case Array -> [Value]
forall a. Vector a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Array
array of
[] -> String -> Parser NodeId
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unexpected GUID format, found empty list"
J.Number Scientific
1 : [Value]
rest -> V1NodeId -> NodeId
NodeIdV1 (V1NodeId -> NodeId) -> Parser V1NodeId -> Parser NodeId
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Value] -> Parser V1NodeId
parseNodeIdV1 [Value]
rest
J.Number Scientific
n : [Value]
_ -> String -> Parser NodeId
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser NodeId) -> String -> Parser NodeId
forall a b. (a -> b) -> a -> b
$ String
"unsupported GUID version: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Scientific -> String
forall a. Show a => a -> String
show Scientific
n
[Value]
_ -> String -> Parser NodeId
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unexpected GUID format, needs to start with a version number"
parseNodeIdV1 :: [J.Value] -> J.Parser V1NodeId
parseNodeIdV1 :: [Value] -> Parser V1NodeId
parseNodeIdV1 (Value
schemaValue : Value
nameValue : Value
firstColumn : [Value]
remainingColumns) =
QualifiedTable -> NESeq Value -> V1NodeId
V1NodeId
(QualifiedTable -> NESeq Value -> V1NodeId)
-> Parser QualifiedTable -> Parser (NESeq Value -> V1NodeId)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (SchemaName -> TableName -> QualifiedTable
forall a. SchemaName -> a -> QualifiedObject a
Postgres.QualifiedObject (SchemaName -> TableName -> QualifiedTable)
-> Parser SchemaName -> Parser (TableName -> QualifiedTable)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser SchemaName
forall a. FromJSON a => Value -> Parser a
J.parseJSON Value
schemaValue Parser (TableName -> QualifiedTable)
-> Parser TableName -> Parser QualifiedTable
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Value -> Parser TableName
forall a. FromJSON a => Value -> Parser a
J.parseJSON Value
nameValue)
Parser (NESeq Value -> V1NodeId)
-> Parser (NESeq Value) -> Parser V1NodeId
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> NESeq Value -> Parser (NESeq Value)
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Value
firstColumn Value -> Seq Value -> NESeq Value
forall a. a -> Seq a -> NESeq a
NESeq.:<|| [Value] -> Seq Value
forall a. [a] -> Seq a
Seq.fromList [Value]
remainingColumns)
parseNodeIdV1 [Value]
_ = String -> Parser V1NodeId
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"GUID version 1: expecting schema name, table name and at least one column value"
data NodeIdVersion
= NIVersion1
| NIVersion2
deriving (Int -> NodeIdVersion -> String -> String
[NodeIdVersion] -> String -> String
NodeIdVersion -> String
(Int -> NodeIdVersion -> String -> String)
-> (NodeIdVersion -> String)
-> ([NodeIdVersion] -> String -> String)
-> Show NodeIdVersion
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> NodeIdVersion -> String -> String
showsPrec :: Int -> NodeIdVersion -> String -> String
$cshow :: NodeIdVersion -> String
show :: NodeIdVersion -> String
$cshowList :: [NodeIdVersion] -> String -> String
showList :: [NodeIdVersion] -> String -> String
Show, NodeIdVersion -> NodeIdVersion -> Bool
(NodeIdVersion -> NodeIdVersion -> Bool)
-> (NodeIdVersion -> NodeIdVersion -> Bool) -> Eq NodeIdVersion
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NodeIdVersion -> NodeIdVersion -> Bool
== :: NodeIdVersion -> NodeIdVersion -> Bool
$c/= :: NodeIdVersion -> NodeIdVersion -> Bool
/= :: NodeIdVersion -> NodeIdVersion -> Bool
Eq)
nodeIdVersionInt :: NodeIdVersion -> Int
nodeIdVersionInt :: NodeIdVersion -> Int
nodeIdVersionInt = \case
NodeIdVersion
NIVersion1 -> Int
1
NodeIdVersion
NIVersion2 -> Int
2
currentNodeIdVersion :: NodeIdVersion
currentNodeIdVersion :: NodeIdVersion
currentNodeIdVersion = NodeIdVersion
NIVersion1
type NodeMap = HashMap SourceName (AB.AnyBackend TableMap)
data NodeInfo b = NodeInfo
{ forall (b :: BackendType). NodeInfo b -> SourceInfo b
nvSourceInfo :: SourceInfo b,
forall (b :: BackendType). NodeInfo b -> SelPermInfo b
nvSelectPermissions :: SelPermInfo b,
forall (b :: BackendType). NodeInfo b -> PrimaryKeyColumns b
nvPrimaryKeys :: PrimaryKeyColumns b,
forall (b :: BackendType).
NodeInfo b
-> AnnFieldsG
b (RemoteRelationshipField UnpreparedValue) (UnpreparedValue b)
nvAnnotatedFields :: IR.AnnFieldsG b (IR.RemoteRelationshipField IR.UnpreparedValue) (IR.UnpreparedValue b)
}
newtype TableMap b = TableMap (HashMap (TableName b) (NodeInfo b))
findNode :: forall b. (Backend b) => SourceName -> TableName b -> NodeMap -> Maybe (NodeInfo b)
findNode :: forall (b :: BackendType).
Backend b =>
SourceName -> TableName b -> NodeMap -> Maybe (NodeInfo b)
findNode SourceName
sourceName TableName b
tableName NodeMap
nodeMap = do
AnyBackend TableMap
anyTableMap <- SourceName -> NodeMap -> Maybe (AnyBackend TableMap)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup SourceName
sourceName NodeMap
nodeMap
TableMap HashMap (TableName b) (NodeInfo b)
tableMap <- forall (b :: BackendType) (i :: BackendType -> *).
HasTag b =>
AnyBackend i -> Maybe (i b)
AB.unpackAnyBackend @b AnyBackend TableMap
anyTableMap
TableName b
-> HashMap (TableName b) (NodeInfo b) -> Maybe (NodeInfo b)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup TableName b
tableName HashMap (TableName b) (NodeInfo b)
tableMap