chore(server): Table -> Native Query object relationships

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10114
GitOrigin-RevId: 0181184d1bc0e851151f86a98c96c97888a10e3e
This commit is contained in:
Daniel Harvey 2023-08-17 16:34:05 +01:00 committed by hasura-bot
parent 334a133573
commit f8d60a74a0
16 changed files with 287 additions and 120 deletions

View File

@ -946,7 +946,15 @@
"BigqueryRUManual": {
"properties": {
"manual_configuration": {
"$ref": "#/components/schemas/BigqueryRelManualTableConfig"
"additionalProperties": true,
"anyOf": [
{
"$ref": "#/components/schemas/BigqueryRelManualTableConfig"
},
{
"$ref": "#/components/schemas/BigqueryRelManualNativeQueryConfig"
}
]
}
},
"required": [
@ -1919,7 +1927,15 @@
"CitusRUManual": {
"properties": {
"manual_configuration": {
"$ref": "#/components/schemas/CitusRelManualTableConfig"
"additionalProperties": true,
"anyOf": [
{
"$ref": "#/components/schemas/CitusRelManualTableConfig"
},
{
"$ref": "#/components/schemas/CitusRelManualNativeQueryConfig"
}
]
}
},
"required": [
@ -2919,7 +2935,15 @@
"CockroachRUManual": {
"properties": {
"manual_configuration": {
"$ref": "#/components/schemas/CockroachRelManualTableConfig"
"additionalProperties": true,
"anyOf": [
{
"$ref": "#/components/schemas/CockroachRelManualTableConfig"
},
{
"$ref": "#/components/schemas/CockroachRelManualNativeQueryConfig"
}
]
}
},
"required": [
@ -4063,7 +4087,15 @@
"DataconnectorRUManual": {
"properties": {
"manual_configuration": {
"$ref": "#/components/schemas/DataconnectorRelManualTableConfig"
"additionalProperties": true,
"anyOf": [
{
"$ref": "#/components/schemas/DataconnectorRelManualTableConfig"
},
{
"$ref": "#/components/schemas/DataconnectorRelManualNativeQueryConfig"
}
]
}
},
"required": [
@ -5768,7 +5800,15 @@
"MssqlRUManual": {
"properties": {
"manual_configuration": {
"$ref": "#/components/schemas/MssqlRelManualTableConfig"
"additionalProperties": true,
"anyOf": [
{
"$ref": "#/components/schemas/MssqlRelManualTableConfig"
},
{
"$ref": "#/components/schemas/MssqlRelManualNativeQueryConfig"
}
]
}
},
"required": [
@ -7123,7 +7163,15 @@
"PostgresRUManual": {
"properties": {
"manual_configuration": {
"$ref": "#/components/schemas/PostgresRelManualTableConfig"
"additionalProperties": true,
"anyOf": [
{
"$ref": "#/components/schemas/PostgresRelManualTableConfig"
},
{
"$ref": "#/components/schemas/PostgresRelManualNativeQueryConfig"
}
]
}
},
"required": [

View File

@ -11,7 +11,6 @@ module Harness.Schema
BackendScalarType (..),
BackendScalarValue (..),
BackendScalarValueType (..),
ManualRelationship (..),
SchemaName (..),
NativeQuery (..),
NativeQueryColumn (..),
@ -31,6 +30,7 @@ module Harness.Schema
untrackRelationships,
mkObjectRelationshipName,
mkArrayRelationshipName,
createTableToNativeQueryRelationship,
trackFunction,
untrackFunction,
trackComputedField,
@ -305,6 +305,14 @@ mkObjectRelationshipName Reference {referenceLocalColumn, referenceTargetTable,
Nothing -> referenceTargetColumn
in referenceTargetTable <> "_by_" <> referenceLocalColumn <> "_to_" <> columnName
-- | Helper to create the object relationship name
mkNativeQueryRelationshipName :: NativeQueryRelationship -> Text
mkNativeQueryRelationshipName NativeQueryRelationship {nqRelationshipLocalColumn, nqRelationshipTarget, nqRelationshipType} =
let joiner = case nqRelationshipType of
ObjectRelationship -> "_object_by_"
ArrayRelationship -> "_array_by_"
in nqRelationshipTarget <> joiner <> nqRelationshipLocalColumn <> "_to_" <> nqRelationshipLocalColumn
-- | Build an 'J.Value' representing a 'BackendType' specific @TableName@.
mkTableField :: BackendTypeConfig -> SchemaName -> Text -> J.Value
mkTableField backendTypeMetadata schemaName tableName =
@ -324,7 +332,7 @@ mkInsertionOrder AfterParent = "after_parent"
-- | Unified track object relationships
trackObjectRelationships :: (HasCallStack) => Table -> TestEnvironment -> IO ()
trackObjectRelationships tbl@(Table {tableName, tableReferences, tableManualRelationships}) testEnvironment = do
trackObjectRelationships tbl@(Table {tableName, tableReferences, tableNativeQueryRelationships, tableManualRelationships}) testEnvironment = do
let backendTypeMetadata = fromMaybe (error "Unknown backend") $ getBackendTypeConfig testEnvironment
localSchema = resolveTableSchema testEnvironment tbl
backendType = BackendType.backendTypeString backendTypeMetadata
@ -381,6 +389,58 @@ trackObjectRelationships tbl@(Table {tableName, tableReferences, tableManualRela
GraphqlEngine.postMetadata_ testEnvironment payload
for_ tableNativeQueryRelationships
$ \relationship ->
GraphqlEngine.postMetadata_
testEnvironment
(createTableToNativeQueryRelationship testEnvironment localSchema tableName relationship)
createTableToNativeQueryRelationship :: TestEnvironment -> SchemaName -> Text -> NativeQueryRelationship -> Value
createTableToNativeQueryRelationship testEnvironment localSchema tableName ref@NativeQueryRelationship {nqRelationshipLocalColumn, nqRelationshipTarget, nqRelationshipTargetColumn, nqRelationshipType} =
let backendTypeMetadata = fromMaybe (error "Unknown backend") $ getBackendTypeConfig testEnvironment
tableField = mkTableField backendTypeMetadata localSchema tableName
source = BackendType.backendSourceName backendTypeMetadata
backendType = BackendType.backendTypeString backendTypeMetadata
requestType = backendType <> "_create_object_relationship"
relationshipName = mkNativeQueryRelationshipName ref
in case nqRelationshipType of
ArrayRelationship ->
let manualConfiguration :: J.Value
manualConfiguration =
J.object
[ "remote_native_query" .= nqRelationshipTarget,
"column_mapping"
.= J.object [K.fromText nqRelationshipLocalColumn .= nqRelationshipTargetColumn],
"insertion_order" .= J.Null
]
in [yaml|
type: *requestType
args:
source: *source
table: *tableField
name: *relationshipName
using:
manual_configuration: *manualConfiguration
|]
ObjectRelationship ->
let manualConfiguration :: J.Value
manualConfiguration =
J.object
[ "remote_native_query" .= nqRelationshipTarget,
"column_mapping"
.= J.object [K.fromText nqRelationshipLocalColumn .= nqRelationshipTargetColumn],
"insertion_order" .= J.Null
]
in [yaml|
type: *requestType
args:
source: *source
table: *tableField
name: *relationshipName
using:
manual_configuration: *manualConfiguration
|]
-- | Helper to create the array relationship name
mkArrayRelationshipName :: Text -> Text -> Text -> [Text] -> Text
mkArrayRelationshipName tableName referenceLocalColumn referenceTargetColumn referenceTargetQualifiers =
@ -391,7 +451,7 @@ mkArrayRelationshipName tableName referenceLocalColumn referenceTargetColumn ref
-- | Unified track array relationships
trackArrayRelationships :: (HasCallStack) => Table -> TestEnvironment -> IO ()
trackArrayRelationships tbl@(Table {tableName, tableReferences, tableManualRelationships}) testEnvironment = do
trackArrayRelationships tbl@(Table {tableName, tableReferences, tableNativeQueryRelationships, tableManualRelationships}) testEnvironment = do
let backendTypeMetadata = fromMaybe (error "Unknown backend") $ getBackendTypeConfig testEnvironment
localSchema = resolveTableSchema testEnvironment tbl
backendType = BackendType.backendTypeString backendTypeMetadata
@ -450,17 +510,23 @@ trackArrayRelationships tbl@(Table {tableName, tableReferences, tableManualRelat
]
payload =
[yaml|
type: *requestType
args:
source: *source
table: *targetTableField
name: *relationshipName
using:
manual_configuration: *manualConfiguration
|]
type: *requestType
args:
source: *source
table: *targetTableField
name: *relationshipName
using:
manual_configuration: *manualConfiguration
|]
GraphqlEngine.postMetadata_ testEnvironment payload
for_ tableNativeQueryRelationships
$ \relationship ->
GraphqlEngine.postMetadata_
testEnvironment
(createTableToNativeQueryRelationship testEnvironment localSchema tableName relationship)
-- | Unified untrack relationships
untrackRelationships :: (HasCallStack) => Table -> TestEnvironment -> IO ()
untrackRelationships Table {tableName, tableReferences, tableManualRelationships} testEnvironment = do

View File

@ -5,7 +5,10 @@ module Harness.Schema.Table
( Table (..),
table,
Reference (..),
RelationshipType (..),
NativeQueryRelationship (..),
reference,
nativeQueryObjectRelationship,
InsertOrder (..),
Column (..),
ScalarType (..),
@ -19,7 +22,6 @@ module Harness.Schema.Table
BackendScalarType (..),
BackendScalarValue (..),
BackendScalarValueType (..),
ManualRelationship (..),
quotedValue,
unquotedValue,
backendScalarValue,
@ -54,6 +56,7 @@ data Table = Table
tablePrimaryKey :: [Text],
tableReferences :: [Reference],
tableManualRelationships :: [Reference],
tableNativeQueryRelationships :: [NativeQueryRelationship],
tableData :: [[ScalarValue]],
tableConstraints :: [Constraint],
tableUniqueIndexes :: [UniqueIndex],
@ -85,6 +88,7 @@ table tableName =
tablePrimaryKey = [],
tableReferences = [],
tableManualRelationships = [],
tableNativeQueryRelationships = [],
tableData = [],
tableConstraints = [],
tableUniqueIndexes = [],
@ -116,17 +120,27 @@ reference localColumn targetTable targetColumn =
referenceCascade = True
}
-- | Type representing manual relationship between tables. This is
-- only used for BigQuery backend currently where additional
-- relationships has to be manually specified.
data ManualRelationship = ManualRelationship
{ relSourceTable :: Text,
relTargetTable :: Text,
relSourceColumn :: Text,
relTargetColumn :: Text
data RelationshipType = ArrayRelationship | ObjectRelationship
deriving (Eq, Show)
-- | Relationship to a Native Query
data NativeQueryRelationship = NativeQueryRelationship
{ nqRelationshipLocalColumn :: Text,
nqRelationshipTarget :: Text,
nqRelationshipTargetColumn :: Text,
nqRelationshipType :: RelationshipType
}
deriving (Show, Eq)
nativeQueryObjectRelationship :: Text -> Text -> Text -> NativeQueryRelationship
nativeQueryObjectRelationship localColumn targetNativeQuery targetColumn =
NativeQueryRelationship
{ nqRelationshipLocalColumn = localColumn,
nqRelationshipTarget = targetNativeQuery,
nqRelationshipTargetColumn = targetColumn,
nqRelationshipType = ObjectRelationship
}
-- | Generic type to construct columns for all backends
data Column = Column
{ columnName :: Text,

View File

@ -233,10 +233,10 @@ mkReferenceSql :: SchemaName -> Schema.Reference -> Text
mkReferenceSql (SchemaName localSchemaName) Schema.Reference {referenceLocalColumn, referenceTargetTable, referenceTargetColumn, referenceTargetQualifiers} =
let schemaName = maybe localSchemaName unSchemaName (resolveReferenceSchema referenceTargetQualifiers)
in [i|
FOREIGN KEY ("#{ referenceLocalColumn }")
REFERENCES "#{ schemaName }"."#{ referenceTargetTable }" ("#{ referenceTargetColumn }")
ON DELETE CASCADE ON UPDATE CASCADE
|]
FOREIGN KEY ("#{ referenceLocalColumn }")
REFERENCES "#{ schemaName }"."#{ referenceTargetTable }" ("#{ referenceTargetColumn }")
ON DELETE CASCADE ON UPDATE CASCADE
|]
uniqueConstraintSql :: Schema.Constraint -> Text
uniqueConstraintSql = \case

View File

@ -141,34 +141,6 @@ trackObjectRelationships (Schema.Table {tableName, tableReferences {-, tableManu
foreign_key_constraint_on: *referenceLocalColumn
|]
{-
for_ tableManualRelationships $ \ref@Reference {referenceLocalColumn, referenceTargetTable, referenceTargetColumn, referenceTargetQualifiers} -> do
let targetSchema = case resolveReferenceSchema referenceTargetQualifiers of
Just schema -> schema
Nothing -> getSchemaName testEnvironment
relationshipName = mkObjectRelationshipName ref
targetTableField = mkTableField backendTypeMetadata targetSchema referenceTargetTable
manualConfiguration :: J.Value
manualConfiguration =
J.object
[ "remote_table" .= targetTableField,
"column_mapping"
.= J.object [K.fromText referenceLocalColumn .= referenceTargetColumn]
]
payload =
[yaml|
type: *requestType
args:
source: *source
table: *tableField
name: *relationshipName
using:
manual_configuration: *manualConfiguration
|]
GraphqlEngine.postMetadata_ testEnvironment payload
-}
-- | Helper to create the object relationship name
mkObjectRelationshipName :: Schema.Reference -> Text
mkObjectRelationshipName Schema.Reference {referenceLocalColumn, referenceTargetTable, referenceTargetColumn, referenceTargetQualifiers} =
@ -188,22 +160,32 @@ trackArrayRelationships ::
Schema.Table ->
env ->
IO ()
trackArrayRelationships (Schema.Table {tableName, tableReferences {-, tableManualRelationships-}}) env = do
trackArrayRelationships (Schema.Table {tableName, tableReferences}) env = do
let localSchema = getter @SchemaName env
source = postgresSourceName $ getter @PostgresSource env
tableField = J.object ["schema" J..= J.String (unSchemaName localSchema), "name" J..= J.String tableName]
for_ tableReferences $ \Schema.Reference {referenceLocalColumn, referenceTargetTable, referenceTargetColumn, referenceTargetQualifiers} -> do
let targetSchema = localSchema
relationshipName = mkArrayRelationshipName tableName referenceTargetColumn referenceLocalColumn referenceTargetQualifiers
targetTableField = J.object ["schema" J..= J.String (unSchemaName targetSchema), "name" J..= J.String referenceTargetTable]
for_ tableReferences
$ \Schema.Reference
{ referenceLocalColumn,
referenceTargetTable,
referenceTargetColumn,
referenceTargetQualifiers
} -> do
let targetSchema = localSchema
relationshipName = mkArrayRelationshipName tableName referenceTargetColumn referenceLocalColumn referenceTargetQualifiers
targetTableField =
J.object
[ "schema" J..= J.String (unSchemaName targetSchema),
"name" J..= J.String referenceTargetTable
]
hgePost
env
200
"/v1/metadata"
[]
[yaml|
hgePost
env
200
"/v1/metadata"
[]
[yaml|
type: pg_create_array_relationship
args:
source: *source
@ -215,36 +197,6 @@ trackArrayRelationships (Schema.Table {tableName, tableReferences {-, tableManua
column: *referenceLocalColumn
|]
-- Unfinished implementation of manual relationships, to be completed when the need arises.
{-
for_ tableManualRelationships $ \Reference {referenceLocalColumn, referenceTargetTable, referenceTargetColumn, referenceTargetQualifiers} -> do
let targetSchema = case resolveReferenceSchema referenceTargetQualifiers of
Just schema -> schema
Nothing -> getSchemaName testEnvironment
relationshipName = mkArrayRelationshipName tableName referenceTargetColumn referenceLocalColumn referenceTargetQualifiers
targetTableField = mkTableField backendTypeMetadata targetSchema referenceTargetTable
manualConfiguration :: J.Value
manualConfiguration =
J.object
[ "remote_table"
.= tableField,
"column_mapping"
.= J.object [K.fromText referenceTargetColumn .= referenceLocalColumn]
]
payload =
[yaml|
type: *requestType
args:
source: *source
table: *targetTableField
name: *relationshipName
using:
manual_configuration: *manualConfiguration
\|]
GraphqlEngine.postMetadata_ testEnvironment payload
-}
-- | Helper to create the array relationship name
mkArrayRelationshipName :: Text -> Text -> Text -> [Text] -> Text
mkArrayRelationshipName tableName referenceLocalColumn referenceTargetColumn referenceTargetQualifiers =

View File

@ -151,11 +151,13 @@ instance PostgresMetadata 'Citus where
case obj of
RUFKeyOn (SameTable _) -> pure ()
RUFKeyOn (RemoteTable targetTable _) -> checkObjectRelationship sourceTableInfo targetTable
RUManual RelManualTableConfigC {} -> pure ()
RUManual RelManualTableConfig {} -> pure ()
RUManual RelManualNativeQueryConfig {} -> pure ()
Right (RelDef _ obj _) ->
case obj of
RUFKeyOn (ArrRelUsingFKeyOn targetTable _col) -> checkArrayRelationship sourceTableInfo targetTable
RUManual RelManualTableConfigC {} -> pure ()
RUManual RelManualTableConfig {} -> pure ()
RUManual RelManualNativeQueryConfig {} -> pure ()
where
lookupTableInfo tableName =
HashMap.lookup tableName tableCache

View File

@ -33,6 +33,7 @@ import Hasura.LogicalModel.Cache (LogicalModelInfo (..))
import Hasura.LogicalModel.Common
import Hasura.LogicalModel.Types (LogicalModelName (..))
import Hasura.Name qualified as Name
import Hasura.NativeQuery.Cache (NativeQueryInfo (_nqiReturns))
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp
import Hasura.RQL.IR.Value
@ -148,7 +149,14 @@ boolExpInternal gqlName selectPermissions fieldInfos description memoizeKey mkAg
-- field_name: field_type_bool_exp
FIRelationship relationshipInfo -> do
case riTarget relationshipInfo of
RelTargetNativeQuery _ -> error "mkField RelTargetNativeQuery"
RelTargetNativeQuery nativeQueryName -> do
logicalModelInfo <- _nqiReturns <$> askNativeQueryInfo nativeQueryName
let remoteLogicalModelPermissions =
(fmap . fmap) (partialSQLExpToUnpreparedValue)
$ maybe annBoolExpTrue spiFilter
$ getSelPermInfoForLogicalModel roleName logicalModelInfo
remoteBoolExp <- lift $ logicalModelBoolExp logicalModelInfo
pure $ fmap (AVRelationship relationshipInfo . RelationshipFilters remoteLogicalModelPermissions) remoteBoolExp
RelTargetTable remoteTable -> do
remoteTableInfo <- askTableInfo $ remoteTable
let remoteTablePermissions =

View File

@ -251,7 +251,9 @@ mkDefaultRelationshipParser ::
SchemaT r m (Maybe (InputFieldsParser n (Maybe (IR.AnnotatedInsertField b (IR.UnpreparedValue b)))))
mkDefaultRelationshipParser backendInsertAction xNestedInserts relationshipInfo = runMaybeT do
otherTableName <- case riTarget relationshipInfo of
RelTargetNativeQuery _ -> error "mkDefaultRelationshipParser RelTargetNativeQuery"
RelTargetNativeQuery _ ->
-- Native Queries do not support mutations atm
hoistMaybe Nothing
RelTargetTable tn -> pure tn
let relName = riName relationshipInfo
otherTableInfo <- askTableInfo otherTableName

View File

@ -147,7 +147,7 @@ orderByExpInternal gqlName description selectPermissions tableFields memoizeKey
FIColumn (SCIArrayColumn _) -> empty
FIRelationship relationshipInfo -> do
case riTarget relationshipInfo of
RelTargetNativeQuery _ -> error "mkField RelTargetNativeQuery"
RelTargetNativeQuery _ -> hoistMaybe Nothing -- we do not support ordering by a nested Native Query yet
RelTargetTable remoteTableName -> do
remoteTableInfo <- askTableInfo remoteTableName
perms <- hoistMaybe $ tableSelectPermissions roleName remoteTableInfo

View File

@ -556,6 +556,7 @@ defaultTableSelectionSet ::
forall b r m n.
( AggregationPredicatesSchema b,
BackendTableSelectSchema b,
BackendNativeQuerySelectSchema b,
Eq (AnnBoolExp b (IR.UnpreparedValue b)),
MonadBuildSchema b r m n
) =>
@ -1290,6 +1291,7 @@ fieldSelection ::
forall b r m n.
( AggregationPredicatesSchema b,
BackendTableSelectSchema b,
BackendNativeQuerySelectSchema b,
Eq (AnnBoolExp b (IR.UnpreparedValue b)),
MonadBuildSchema b r m n
) =>
@ -1512,20 +1514,18 @@ relationshipField ::
forall b r m n.
( AggregationPredicatesSchema b,
BackendTableSelectSchema b,
BackendNativeQuerySelectSchema b,
Eq (AnnBoolExp b (IR.UnpreparedValue b)),
MonadBuildSchema b r m n
) =>
TableName b ->
RelInfo b ->
SchemaT r m (Maybe [FieldParser n (AnnotatedField b)])
relationshipField table ri = runMaybeT do
relationshipField table ri@RelInfo {riTarget = RelTargetTable otherTableName} = runMaybeT do
tCase <- retrieve $ _rscNamingConvention . _siCustomization @b
roleName <- retrieve scRole
optimizePermissionFilters <- retrieve Options.soOptimizePermissionFilters
tableInfo <- lift $ askTableInfo @b table
otherTableName <- case riTarget ri of
RelTargetNativeQuery _ -> error "relationshipField RelTargetNativeQuery"
RelTargetTable tn -> pure tn
otherTableInfo <- lift $ askTableInfo otherTableName
tablePerms <- hoistMaybe $ tableSelectPermissions roleName tableInfo
remotePerms <- hoistMaybe $ tableSelectPermissions roleName otherTableInfo
@ -1661,3 +1661,24 @@ relationshipField table ri = runMaybeT do
fmap (IR.AFArrayRelation . IR.ASAggregate . IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable) <$> remoteAggField,
fmap (IR.AFArrayRelation . IR.ASConnection . IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable) <$> remoteConnectionField
]
relationshipField _table ri@RelInfo {riTarget = RelTargetNativeQuery nativeQueryName} = runMaybeT do
relFieldName <- lift $ textToName $ relNameToTxt $ riName ri
case riType ri of
ObjRel -> do
nativeQueryInfo <- askNativeQueryInfo nativeQueryName
let objectRelDesc = Just $ G.Description "An object relationship"
nativeQueryParser <-
MaybeT $ selectNativeQueryObject nativeQueryInfo relFieldName objectRelDesc
-- this only affects the generated GraphQL type
let nullability = Nullable
pure
$ pure
$ nativeQueryParser
<&> \selectExp ->
IR.AFObjectRelation (IR.AnnRelationSelectG (riName ri) (riMapping ri) nullability selectExp)
ArrRel -> throw500 "Table -> Native Query array relationships not supported"

View File

@ -30,7 +30,9 @@ import Hasura.GraphQL.Schema.Common
import Hasura.GraphQL.Schema.Parser (Kind (..), Parser)
import Hasura.GraphQL.Schema.Parser qualified as P
import Hasura.GraphQL.Schema.Typename
import Hasura.LogicalModel.Common (getSelPermInfoForLogicalModel)
import Hasura.Name qualified as Name
import Hasura.NativeQuery.Cache (NativeQueryInfo (_nqiReturns))
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp (AnnRedactionExpPartialSQL, AnnRedactionExpUnpreparedValue)
import Hasura.RQL.Types.Backend
@ -249,7 +251,9 @@ tableSelectFields tableInfo = do
canBeSelected role permissions (FIColumn _naiColumnInfo)
canBeSelected role _ (FIRelationship relationshipInfo) = do
case riTarget relationshipInfo of
RelTargetNativeQuery _ -> error "tableSelectFields RelTargetNativeQuery"
RelTargetNativeQuery nativeQueryName -> do
nativeQueryInfo <- askNativeQueryInfo nativeQueryName
pure $! isJust $ getSelPermInfoForLogicalModel @b role (_nqiReturns nativeQueryInfo)
RelTargetTable tableName -> do
tableInfo' <- askTableInfo tableName
pure $! isJust $ tableSelectPermissions @b role tableInfo'

View File

@ -2,6 +2,7 @@ module Hasura.LogicalModel.Common
( columnsFromFields,
logicalModelFieldsToFieldInfo,
getSelPermInfoForLogicalModel,
logicalModelPermissions,
)
where
@ -9,10 +10,14 @@ import Data.Bifunctor (bimap)
import Data.HashMap.Strict qualified as HashMap
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
import Data.Text.Extended (ToTxt (toTxt))
import Hasura.GraphQL.Schema.Common
( partialSQLExpToUnpreparedValue,
)
import Hasura.LogicalModel.Cache
import Hasura.LogicalModel.NullableScalarType (NullableScalarType (..))
import Hasura.LogicalModel.Types (LogicalModelField (..), LogicalModelType (..), LogicalModelTypeArray (..), LogicalModelTypeReference (..), LogicalModelTypeScalar (..))
import Hasura.Prelude
import Hasura.RQL.IR qualified as IR
import Hasura.RQL.IR.BoolExp (AnnRedactionExp (..), gBoolExpTrue)
import Hasura.RQL.Types.Backend (Backend (..))
import Hasura.RQL.Types.Column (ColumnInfo (..), ColumnMutability (..), ColumnType (..), NestedArrayInfo (..), NestedObjectInfo (..), StructuredColumnInfo (..), fromCol)
@ -21,6 +26,19 @@ import Hasura.RQL.Types.Roles (RoleName, adminRoleName)
import Hasura.Table.Cache (FieldInfo (..), FieldInfoMap, RolePermInfo (..), SelPermInfo (..))
import Language.GraphQL.Draft.Syntax qualified as G
-- | build select permissions for logical model
logicalModelPermissions ::
(Backend b) =>
LogicalModelInfo b ->
RoleName ->
Maybe (IR.TablePermG b (IR.UnpreparedValue b))
logicalModelPermissions logicalModel roleName = do
getSelPermInfoForLogicalModel roleName logicalModel <&> \selectPermissions ->
IR.TablePerm
{ IR._tpFilter = fmap partialSQLExpToUnpreparedValue <$> spiFilter selectPermissions,
IR._tpLimit = spiLimit selectPermissions
}
columnsFromFields ::
InsOrdHashMap.InsOrdHashMap k (LogicalModelField b) ->
InsOrdHashMap.InsOrdHashMap k (NullableScalarType b)

View File

@ -134,7 +134,30 @@ defaultBuildObjectRelationshipInfo ::
ObjRelDef b ->
m (RelInfo b, Seq SchemaDependency)
defaultBuildObjectRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case ru of
RUManual (RelManualTableConfigC {rmtTable = refqt, rmtCommon = common}) -> do
RUManual (RelManualNativeQueryConfig (RelManualNativeQueryConfigC {rmnNativeQueryName = refqt, rmnCommon = common})) -> do
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
io = fromMaybe BeforeParent $ rmInsertOrder common
mkNativeQueryDependency nativeQueryName reason col =
SchemaDependency
( SOSourceObj source
$ AB.mkAnyBackend
$ SOINativeQueryObj @b nativeQueryName
$ NQOCol @b col
)
reason
mkDependency tableName reason col =
SchemaDependency
( SOSourceObj source
$ AB.mkAnyBackend
$ SOITableObj @b tableName
$ TOCol @b col
)
reason
dependencies =
(mkDependency qt DRLeftColumn <$> Seq.fromList lCols)
<> (mkNativeQueryDependency refqt DRRightColumn <$> Seq.fromList rCols)
pure (RelInfo rn ObjRel (rmColumns common) (RelTargetNativeQuery refqt) True io, dependencies)
RUManual (RelManualTableConfig (RelManualTableConfigC {rmtTable = refqt, rmtCommon = common})) -> do
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
io = fromMaybe BeforeParent $ rmInsertOrder common
mkDependency tableName reason col =
@ -242,7 +265,9 @@ defaultBuildArrayRelationshipInfo ::
ArrRelDef b ->
m (RelInfo b, Seq SchemaDependency)
defaultBuildArrayRelationshipInfo source foreignKeys qt (RelDef rn ru _) = case ru of
RUManual (RelManualTableConfigC {rmtTable = refqt, rmtCommon = common}) -> do
RUManual (RelManualNativeQueryConfig (RelManualNativeQueryConfigC {rmnNativeQueryName = _refqt, rmnCommon = _common})) ->
throw500 "table -> native query array relationships not implemented"
RUManual (RelManualTableConfig (RelManualTableConfigC {rmtTable = refqt, rmtCommon = common})) -> do
let (lCols, rCols) = unzip $ HashMap.toList $ rmColumns common
deps =
( fmap

View File

@ -930,6 +930,7 @@ recreateSystemMetadata = do
arrayRel name using = Right $ RelDef (RelName name) using Nothing
manualConfig schemaName tableName columns =
RUManual
$ RelManualTableConfig
$ RelManualTableConfigC
(QualifiedObject schemaName tableName)
(RelManualCommon (HashMap.fromList columns) Nothing)

View File

@ -301,9 +301,11 @@ updateRelDefs source qt rn renameTable = do
updateObjRelDef (oldQT, newQT) =
rdUsing %~ \case
RUFKeyOn fk -> RUFKeyOn fk
RUManual (RelManualTableConfigC origQT (RelManualCommon rmCols rmIO)) ->
RUManual (RelManualTableConfig (RelManualTableConfigC origQT (RelManualCommon rmCols rmIO))) ->
let updQT = bool origQT newQT $ oldQT == origQT
in RUManual $ RelManualTableConfigC updQT (RelManualCommon rmCols rmIO)
in RUManual $ RelManualTableConfig $ RelManualTableConfigC updQT (RelManualCommon rmCols rmIO)
RUManual (RelManualNativeQueryConfig nqc) ->
RUManual (RelManualNativeQueryConfig nqc)
updateArrRelDef :: RenameTable b -> ArrRelDef b -> ArrRelDef b
updateArrRelDef (oldQT, newQT) =
@ -311,9 +313,11 @@ updateRelDefs source qt rn renameTable = do
RUFKeyOn (ArrRelUsingFKeyOn origQT c) ->
let updQT = getUpdQT origQT
in RUFKeyOn $ ArrRelUsingFKeyOn updQT c
RUManual (RelManualTableConfigC origQT (RelManualCommon rmCols rmIO)) ->
RUManual (RelManualTableConfig (RelManualTableConfigC origQT (RelManualCommon rmCols rmIO))) ->
let updQT = getUpdQT origQT
in RUManual $ RelManualTableConfigC updQT (RelManualCommon rmCols rmIO)
in RUManual $ RelManualTableConfig $ RelManualTableConfigC updQT (RelManualCommon rmCols rmIO)
RUManual (RelManualNativeQueryConfig nqc) ->
RUManual (RelManualNativeQueryConfig nqc)
where
getUpdQT origQT = bool origQT newQT $ oldQT == origQT
@ -741,10 +745,12 @@ updateRelManualConfig ::
TableName b ->
TableName b ->
RenameCol b ->
RelManualTableConfig b ->
RelManualTableConfig b
updateRelManualConfig fromQT toQT rnCol (RelManualTableConfigC tn (RelManualCommon colMap io)) =
RelManualTableConfigC tn (RelManualCommon (updateColMap fromQT toQT rnCol colMap) io)
RelManualConfig b ->
RelManualConfig b
updateRelManualConfig fromQT toQT rnCol (RelManualTableConfig (RelManualTableConfigC tn (RelManualCommon colMap io))) =
RelManualTableConfig (RelManualTableConfigC tn (RelManualCommon (updateColMap fromQT toQT rnCol colMap) io))
updateRelManualConfig fromQT toQT rnCol (RelManualNativeQueryConfig (RelManualNativeQueryConfigC nqn (RelManualCommon colMap io))) =
RelManualNativeQueryConfig (RelManualNativeQueryConfigC nqn (RelManualCommon (updateColMap fromQT toQT rnCol colMap) io))
updateColMap ::
forall b.

View File

@ -149,7 +149,7 @@ instance (Backend b) => AC.HasObjectCodec (RelManualCommon b) where
data RelUsing (b :: BackendType) a
= RUFKeyOn a
| RUManual (RelManualTableConfig b)
| RUManual (RelManualConfig b)
deriving (Show, Eq, Generic)
instance (Backend b, HasCodec a, Typeable a) => HasCodec (RelUsing b a) where