mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-10-26 10:20:54 +03:00
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:
parent
334a133573
commit
f8d60a74a0
@ -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": [
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user