mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-09-20 15:09:02 +03:00
server/mssql: integrate insert mutation schema parser for MSSQL backend
> ### Description > This PR is an incremental work towards [enabling insert mutations on MSSQL](https://github.com/hasura/graphql-engine-mono/pull/1974). In this PR, we generate insert mutation schema parser for MSSQL backend. ### Changelog - [ ] `CHANGELOG.md` is updated with user-facing content relevant to this PR. If no changelog is required, then add the `no-changelog-required` label. ### Affected components - [x] Server https://github.com/hasura/graphql-engine-mono/pull/2141 GitOrigin-RevId: 8595008dece35f7fded9c52e134de8b97b64f53f
This commit is contained in:
parent
b50df8a24b
commit
7ca48decfb
@ -96,6 +96,9 @@ resolveSource sourceConfig =
|
||||
case mode of
|
||||
Nullable -> True
|
||||
_ -> False
|
||||
, prciIsIdentity = notIdentityColumn -- TODO: Determine the identity-ness of BigQuery columns. Until then we assume them as not identity.
|
||||
-- For more details refer https://en.wikipedia.org/wiki/Identity_column.
|
||||
-- issue: https://github.com/hasura/graphql-engine/issues/7450
|
||||
, prciDescription = Nothing
|
||||
}
|
||||
| (position, RestFieldSchema {name, type', mode}) <-
|
||||
|
@ -45,8 +45,9 @@ instance BackendSchema 'BigQuery where
|
||||
buildFunctionMutationFields = bqBuildFunctionMutationFields
|
||||
|
||||
-- backend extensions
|
||||
relayExtension = Nothing
|
||||
nodesAggExtension = Just ()
|
||||
relayExtension = Nothing
|
||||
nodesAggExtension = Just ()
|
||||
nestedInsertsExtension = Nothing
|
||||
|
||||
-- table arguments
|
||||
tableArguments = bqTableArgs
|
||||
|
@ -39,6 +39,7 @@ instance Backend 'BigQuery where
|
||||
type XComputedField 'BigQuery = XDisable
|
||||
type XRelay 'BigQuery = XDisable
|
||||
type XNodesAgg 'BigQuery = XEnable
|
||||
type XNestedInserts 'BigQuery = XDisable
|
||||
|
||||
type ExtraTableMetadata 'BigQuery = ()
|
||||
|
||||
|
@ -212,7 +212,7 @@ msDBMutationPlan
|
||||
-> QueryTagsComment
|
||||
-> m (DBStepInfo 'MSSQL)
|
||||
msDBMutationPlan _userInfo _stringifyNum _sourceName _sourceConfig _mrf _queryTags =
|
||||
throw500 "mutations are not supported in MSSQL; this should be unreachable"
|
||||
throw400 NotSupported "mutations are not supported in MSSQL"
|
||||
|
||||
|
||||
-- subscription
|
||||
|
@ -37,7 +37,7 @@ instance BackendSchema 'MSSQL where
|
||||
-- top level parsers
|
||||
buildTableQueryFields = GSB.buildTableQueryFields
|
||||
buildTableRelayQueryFields = msBuildTableRelayQueryFields
|
||||
buildTableInsertMutationFields = msBuildTableInsertMutationFields
|
||||
buildTableInsertMutationFields = GSB.buildTableInsertMutationFields
|
||||
buildTableUpdateMutationFields = msBuildTableUpdateMutationFields
|
||||
buildTableDeleteMutationFields = msBuildTableDeleteMutationFields
|
||||
buildFunctionQueryFields = msBuildFunctionQueryFields
|
||||
@ -45,8 +45,9 @@ instance BackendSchema 'MSSQL where
|
||||
buildFunctionMutationFields = msBuildFunctionMutationFields
|
||||
|
||||
-- backend extensions
|
||||
relayExtension = Nothing
|
||||
nodesAggExtension = Just ()
|
||||
relayExtension = Nothing
|
||||
nodesAggExtension = Just ()
|
||||
nestedInsertsExtension = Nothing
|
||||
|
||||
-- table arguments
|
||||
tableArguments = msTableArgs
|
||||
@ -82,20 +83,6 @@ msBuildTableRelayQueryFields
|
||||
msBuildTableRelayQueryFields _sourceName _sourceInfo _tableName _tableInfo _gqlName _pkeyColumns _selPerms =
|
||||
pure []
|
||||
|
||||
msBuildTableInsertMutationFields
|
||||
:: MonadBuildSchema 'MSSQL r m n
|
||||
=> SourceName
|
||||
-> SourceConfig 'MSSQL
|
||||
-> TableName 'MSSQL
|
||||
-> TableInfo 'MSSQL
|
||||
-> G.Name
|
||||
-> InsPermInfo 'MSSQL
|
||||
-> Maybe (SelPermInfo 'MSSQL)
|
||||
-> Maybe (UpdPermInfo 'MSSQL)
|
||||
-> m [FieldParser n (MutationRootField UnpreparedValue)]
|
||||
msBuildTableInsertMutationFields _sourceName _sourceInfo _tableName _tableInfo _gqlName _insPerms _selPerms _updPerms =
|
||||
pure []
|
||||
|
||||
msBuildTableUpdateMutationFields
|
||||
:: MonadBuildSchema 'MSSQL r m n
|
||||
=> SourceName
|
||||
|
@ -42,6 +42,7 @@ instance Backend 'MSSQL where
|
||||
type XComputedField 'MSSQL = XDisable
|
||||
type XRelay 'MSSQL = XDisable
|
||||
type XNodesAgg 'MSSQL = XEnable
|
||||
type XNestedInserts 'MSSQL = XDisable
|
||||
|
||||
functionArgScalarType :: FunctionArgType 'MSSQL -> ScalarType 'MSSQL
|
||||
functionArgScalarType = absurd
|
||||
|
@ -70,6 +70,7 @@ data SysColumn = SysColumn
|
||||
, scColumnId :: Int
|
||||
, scUserTypeId :: Int
|
||||
, scIsNullable :: Bool
|
||||
, scIsIdentity :: IsIdentityColumn
|
||||
, scJoinedSysType :: SysType
|
||||
, scJoinedForeignKeyColumns :: [SysForeignKeyColumn]
|
||||
} deriving (Show, Generic)
|
||||
@ -135,6 +136,7 @@ transformColumn columnInfo =
|
||||
-- or dropped. We assume here that this arbitrary column id can
|
||||
-- serve the same purpose.
|
||||
prciIsNullable = scIsNullable columnInfo
|
||||
prciIsIdentity = scIsIdentity columnInfo
|
||||
prciDescription = Nothing
|
||||
prciType = parseScalarType $ styName $ scJoinedSysType columnInfo
|
||||
foreignKeys = scJoinedForeignKeyColumns columnInfo <&> \foreignKeyColumn ->
|
||||
|
@ -46,6 +46,7 @@ instance BackendSchema 'MySQL where
|
||||
computedField = error "computedField: MySQL backend does not support this operation yet."
|
||||
node = error "node: MySQL backend does not support this operation yet."
|
||||
columnDefaultValue = error "columnDefaultValue: MySQL backend does not support this operation yet."
|
||||
nestedInsertsExtension = Nothing
|
||||
|
||||
mysqlTableArgs
|
||||
:: forall r m n
|
||||
|
@ -38,6 +38,7 @@ instance Backend 'MySQL where
|
||||
type XRelay 'MySQL = Void
|
||||
type XNodesAgg 'MySQL = XEnable
|
||||
type ExtraTableMetadata 'MySQL = ()
|
||||
type XNestedInserts 'MySQL = XDisable
|
||||
|
||||
functionArgScalarType :: FunctionArgType 'MySQL -> ScalarType 'MySQL
|
||||
functionArgScalarType = error "functionArgScalarType: not implemented yet"
|
||||
|
@ -46,6 +46,9 @@ mergeMetadata InformationSchema{..} =
|
||||
, prciPosition = fromIntegral isOrdinalPosition
|
||||
, prciType = parseMySQLScalarType isColumnType -- TODO: This needs to become more precise by considering Field length and character-set
|
||||
, prciIsNullable = isIsNullable == "YES" -- ref: https://dev.mysql.com/doc/refman/8.0/en/information-schema-columns-table.html
|
||||
, prciIsIdentity = notIdentityColumn -- TODO: The identity-ness of column is not explicitly available in MySQL INFORMATION_SCHEMA.COLUMNS table.
|
||||
-- Determine this value from 'EXTRA' field. Till then we assume it as not identity.
|
||||
-- issue: https://github.com/hasura/graphql-engine/issues/7450
|
||||
, prciDescription = Just $ G.Description isColumnComment
|
||||
}
|
||||
]
|
||||
|
@ -80,14 +80,14 @@ insertMultipleObjects multiObjIns additionalColumns userInfo mutationOutput plan
|
||||
bool withoutRelsInsert withRelsInsert anyRelsToInsert
|
||||
where
|
||||
IR.AnnIns insObjs table conflictClause checkCondition columnInfos defVals = multiObjIns
|
||||
allInsObjRels = concatMap IR._aioObjRels insObjs
|
||||
allInsArrRels = concatMap IR._aioArrRels insObjs
|
||||
allInsObjRels = concatMap IR.getInsertObjectRelationships insObjs
|
||||
allInsArrRels = concatMap IR.getInsertArrayRelationships insObjs
|
||||
anyRelsToInsert = not $ null allInsArrRels && null allInsObjRels
|
||||
|
||||
withoutRelsInsert = do
|
||||
indexedForM_ (IR._aioColumns <$> insObjs) \column ->
|
||||
indexedForM_ (IR.getInsertColumns <$> insObjs) \column ->
|
||||
validateInsert (map fst column) [] (map fst additionalColumns)
|
||||
let columnValues = map (mkSQLRow defVals) $ union additionalColumns . IR._aioColumns <$> insObjs
|
||||
let columnValues = map (mkSQLRow defVals) $ union additionalColumns . IR.getInsertColumns <$> insObjs
|
||||
columnNames = Map.keys defVals
|
||||
insertQuery = IR.InsertQueryP1
|
||||
table
|
||||
@ -151,7 +151,9 @@ insertObject singleObjIns additionalColumns userInfo planVars stringifyNum = Tra
|
||||
return (totAffRows, colValM)
|
||||
where
|
||||
IR.AnnIns (IR.Single annObj) table onConflict checkCond allColumns defaultValues = singleObjIns
|
||||
IR.AnnInsObj columns objectRels arrayRels = annObj
|
||||
columns = IR.getInsertColumns annObj
|
||||
objectRels = IR.getInsertObjectRelationships annObj
|
||||
arrayRels = IR.getInsertArrayRelationships annObj
|
||||
|
||||
afterInsert, beforeInsert :: [IR.ObjRelIns ('Postgres pgKind) PG.SQLExp]
|
||||
(afterInsert, beforeInsert) =
|
||||
|
@ -129,8 +129,9 @@ instance
|
||||
tableArguments = defaultTableArgs
|
||||
|
||||
-- backend extensions
|
||||
relayExtension = pgkRelayExtension @pgKind
|
||||
nodesAggExtension = Just ()
|
||||
relayExtension = pgkRelayExtension @pgKind
|
||||
nodesAggExtension = Just ()
|
||||
nestedInsertsExtension = Just ()
|
||||
|
||||
-- indivdual components
|
||||
columnParser = columnParser
|
||||
|
@ -77,6 +77,7 @@ instance
|
||||
type XComputedField ('Postgres pgKind) = XEnable
|
||||
type XRelay ('Postgres pgKind) = XEnable
|
||||
type XNodesAgg ('Postgres pgKind) = XEnable
|
||||
type XNestedInserts ('Postgres pgKind) = XEnable
|
||||
|
||||
functionArgScalarType = PG.mkFunctionArgScalarType
|
||||
isComparableType = PG.isComparableType
|
||||
|
@ -277,11 +277,11 @@ resolveAsyncActionQuery userInfo annAction =
|
||||
RS.mkAnnColumnField (mkPGColumnInfo columnInfoArgs) Nothing Nothing
|
||||
|
||||
mkPGColumnInfo (column', columnType) =
|
||||
ColumnInfo column' (G.unsafeMkName $ getPGColTxt column') 0 (ColumnScalar columnType) True Nothing
|
||||
ColumnInfo column' (G.unsafeMkName $ getPGColTxt column') 0 (ColumnScalar columnType) True notIdentityColumn Nothing
|
||||
|
||||
tableBoolExpression =
|
||||
let actionIdColumnInfo = ColumnInfo (unsafePGCol "id") $$(G.litName "id")
|
||||
0 (ColumnScalar PGUUID) False Nothing
|
||||
0 (ColumnScalar PGUUID) False notIdentityColumn Nothing
|
||||
actionIdColumnEq = BoolFld $ AVColumn actionIdColumnInfo [AEQ True $ UVLiteral $ S.SELit $ actionIdToText actionId]
|
||||
sessionVarsColumnInfo = mkPGColumnInfo sessionVarsColumn
|
||||
sessionVarValue = UVParameter Nothing $ ColumnValue (ColumnScalar PGJSONB) $
|
||||
|
@ -201,7 +201,7 @@ actionOutputFields outputType annotatedObject = do
|
||||
AOFTScalar def -> customScalarParser def
|
||||
AOFTEnum def -> customEnumParser def
|
||||
pgColumnInfo =
|
||||
ColumnInfo (unsafePGCol $ G.unName fieldName) fieldName 0 (ColumnScalar PGJSON) (G.isNullable gType) Nothing
|
||||
ColumnInfo (unsafePGCol $ G.unName fieldName) fieldName 0 (ColumnScalar PGJSON) (G.isNullable gType) notIdentityColumn Nothing
|
||||
in P.wrapFieldParser gType selection $> RQL.mkAnnColumnField pgColumnInfo Nothing Nothing
|
||||
|
||||
relationshipFieldParser
|
||||
|
@ -45,7 +45,7 @@ import qualified Hasura.RQL.IR.Select as IR
|
||||
import qualified Hasura.RQL.IR.Update as IR
|
||||
|
||||
import Hasura.Base.Error
|
||||
import Hasura.GraphQL.Parser
|
||||
import Hasura.GraphQL.Parser hiding (Type)
|
||||
import Hasura.GraphQL.Schema.Common
|
||||
import Hasura.RQL.IR
|
||||
import Hasura.RQL.Types hiding (EnumValueInfo)
|
||||
@ -154,6 +154,7 @@ class Backend b => BackendSchema (b :: BackendType) where
|
||||
-- backend extensions
|
||||
relayExtension :: Maybe (XRelay b)
|
||||
nodesAggExtension :: Maybe (XNodesAgg b)
|
||||
nestedInsertsExtension :: Maybe (XNestedInserts b)
|
||||
|
||||
-- individual components
|
||||
columnParser
|
||||
|
@ -111,7 +111,7 @@ tableFieldsInput
|
||||
=> SourceName
|
||||
-> TableInfo b -- ^ qualified name of the table
|
||||
-> InsPermInfo b -- ^ insert permissions of the table
|
||||
-> m (Parser 'Input n (IR.AnnInsObj b (UnpreparedValue b)))
|
||||
-> m (Parser 'Input n (IR.AnnotatedInsertRow b (UnpreparedValue b)))
|
||||
tableFieldsInput sourceName tableInfo insertPerms = memoizeOn 'tableFieldsInput (sourceName, tableName) do
|
||||
tableGQLName <- getTableGQLName tableInfo
|
||||
roleName <- askRoleName
|
||||
@ -120,12 +120,14 @@ tableFieldsInput sourceName tableInfo insertPerms = memoizeOn 'tableFieldsInput
|
||||
FIComputedField _ -> pure Nothing
|
||||
FIRemoteRelationship _ -> pure Nothing
|
||||
FIColumn columnInfo ->
|
||||
whenMaybe (Set.member (pgiColumn columnInfo) (ipiCols insertPerms)) do
|
||||
-- Value of an identity column is generated by the database. We cannot a insert into it. So, identity
|
||||
-- columns are omitted in the insert fields input.
|
||||
whenMaybe (Set.member (pgiColumn columnInfo) (ipiCols insertPerms) && not (isIdentityColumn $ pgiIsIdentity columnInfo)) do
|
||||
let columnName = pgiName columnInfo
|
||||
columnDesc = pgiDescription columnInfo
|
||||
fieldParser <- columnParser (pgiType columnInfo) (G.Nullability $ pgiIsNullable columnInfo)
|
||||
pure $ P.fieldOptional columnName columnDesc fieldParser `mapField`
|
||||
\(mkParameter -> value) -> IR.AnnInsObj [(pgiColumn columnInfo, value)] [] []
|
||||
\(mkParameter -> value) -> IR.AIColumn (pgiColumn columnInfo, value)
|
||||
FIRelationship relationshipInfo -> runMaybeT $ do
|
||||
let otherTableName = riRTable relationshipInfo
|
||||
relName = riName relationshipInfo
|
||||
@ -135,20 +137,21 @@ tableFieldsInput sourceName tableInfo insertPerms = memoizeOn 'tableFieldsInput
|
||||
insPerms <- hoistMaybe $ _permIns permissions
|
||||
let selPerms = _permSel permissions
|
||||
updPerms = _permUpd permissions
|
||||
xNestedInserts <- hoistMaybe (nestedInsertsExtension @b)
|
||||
lift $ case riType relationshipInfo of
|
||||
ObjRel -> do
|
||||
parser <- objectRelationshipInput sourceName otherTableInfo insPerms selPerms updPerms
|
||||
pure $ P.fieldOptional relFieldName Nothing parser `mapField`
|
||||
\objRelIns -> IR.AnnInsObj [] [IR.RelIns objRelIns relationshipInfo] []
|
||||
\objRelIns -> IR.AIObjectRelationship xNestedInserts $ IR.RelIns objRelIns relationshipInfo
|
||||
ArrRel -> do
|
||||
parser <- P.nullable <$> arrayRelationshipInput sourceName otherTableInfo insPerms selPerms updPerms
|
||||
pure $ P.fieldOptional relFieldName Nothing parser <&> \arrRelIns -> do
|
||||
rel <- join arrRelIns
|
||||
Just $ IR.AnnInsObj [] [] [IR.RelIns rel relationshipInfo | not $ null $ IR._aiInsObj rel]
|
||||
IR.AIArrayRelationship xNestedInserts <$>
|
||||
if not (null $ IR._aiInsObj rel) then Just (IR.RelIns rel relationshipInfo) else Nothing
|
||||
let objectName = tableGQLName <> $$(G.litName "_insert_input")
|
||||
objectDesc = G.Description $ "input type for inserting data into table " <>> tableName
|
||||
pure $ P.object objectName (Just objectDesc) $ catMaybes <$> sequenceA objectFields
|
||||
<&> mconcat
|
||||
where
|
||||
tableName = tableInfoName tableInfo
|
||||
|
||||
@ -207,7 +210,7 @@ arrayRelationshipInput sourceName tableInfo insertPerms selectPerms updatePerms
|
||||
mkInsertObject
|
||||
:: forall b f
|
||||
. BackendSchema b
|
||||
=> f (IR.AnnInsObj b (UnpreparedValue b))
|
||||
=> f (IR.AnnotatedInsertRow b (UnpreparedValue b))
|
||||
-> TableName b
|
||||
-> [ColumnInfo b]
|
||||
-> Maybe (IR.ConflictClauseP1 b (UnpreparedValue b))
|
||||
@ -222,7 +225,7 @@ mkInsertObject objects table columns conflictClause insertPerms updatePerms =
|
||||
, _aiTableCols = columns
|
||||
, _aiDefVals = defaultValues
|
||||
}
|
||||
where insertCheck = (fmap . fmap) partialSQLExpToUnpreparedValue $ ipiCheck insertPerms
|
||||
where insertCheck = fmap partialSQLExpToUnpreparedValue <$> ipiCheck insertPerms
|
||||
updateCheck = (fmap . fmap) partialSQLExpToUnpreparedValue <$> (upiCheck =<< updatePerms)
|
||||
defaultValues = Map.union (partialSQLExpToUnpreparedValue <$> ipiSet insertPerms)
|
||||
$ Map.fromList [(column, UVLiteral $ columnDefaultValue @b column) | column <- pgiColumn <$> columns]
|
||||
@ -260,7 +263,7 @@ conflictObject sourceName tableInfo selectPerms updatePerms = runMaybeT $ do
|
||||
pure $ case columns of
|
||||
[] -> IR.CP1DoNothing $ Just constraint
|
||||
_ -> IR.CP1Update constraint columns preSetColumns $
|
||||
BoolAnd $ catMaybes [whereExp, Just $ (fmap . fmap) partialSQLExpToUnpreparedValue $ upiFilter updatePerms]
|
||||
BoolAnd $ catMaybes [whereExp, Just (fmap partialSQLExpToUnpreparedValue <$> upiFilter updatePerms)]
|
||||
pure $ P.object objectName (Just objectDesc) fieldsParser
|
||||
where preSetColumns = partialSQLExpToUnpreparedValue <$> upiSet updatePerms
|
||||
|
||||
@ -363,7 +366,7 @@ mkUpdateObject table columns updatePerms ((opExps, whereExp), mutationOutput) =
|
||||
, IR.uqp1AllCols = columns
|
||||
}
|
||||
where
|
||||
permissionFilter = (fmap . fmap) partialSQLExpToUnpreparedValue $ upiFilter updatePerms
|
||||
permissionFilter = fmap partialSQLExpToUnpreparedValue <$> upiFilter updatePerms
|
||||
checkExp = maybe annBoolExpTrue ((fmap . fmap) partialSQLExpToUnpreparedValue) $ upiCheck updatePerms
|
||||
|
||||
|
||||
@ -424,7 +427,7 @@ mkDeleteObject table columns deletePerms (whereExp, mutationOutput) =
|
||||
, IR.dqp1AllCols = columns
|
||||
}
|
||||
where
|
||||
permissionFilter = (fmap . fmap) partialSQLExpToUnpreparedValue $ dpiFilter deletePerms
|
||||
permissionFilter = fmap partialSQLExpToUnpreparedValue <$> dpiFilter deletePerms
|
||||
|
||||
|
||||
-- common
|
||||
|
@ -335,8 +335,8 @@ alterColumnsInMetadata
|
||||
-> TableName b
|
||||
-> m ()
|
||||
alterColumnsInMetadata source alteredCols fields sc tn = for_ alteredCols $
|
||||
\( RawColumnInfo oldName _ oldType _ _
|
||||
, RawColumnInfo newName _ newType _ _ ) -> do
|
||||
\( RawColumnInfo{prciName = oldName, prciType = oldType}
|
||||
, RawColumnInfo{prciName = newName, prciType = newType}) -> do
|
||||
if | oldName /= newName ->
|
||||
renameColumnInMetadata oldName newName source tn fields
|
||||
|
||||
|
@ -512,6 +512,7 @@ buildTableCache = Inc.cache proc (source, sourceConfig, dbTablesMeta, tableBuild
|
||||
, pgiPosition = prciPosition rawInfo
|
||||
, pgiType = resolvedType
|
||||
, pgiIsNullable = prciIsNullable rawInfo
|
||||
, pgiIsIdentity = prciIsIdentity rawInfo
|
||||
, pgiDescription = prciDescription rawInfo
|
||||
}
|
||||
where
|
||||
|
@ -16,6 +16,8 @@ module Hasura.RQL.IR.Insert where
|
||||
|
||||
import Hasura.Prelude
|
||||
|
||||
import Control.Lens ((^?))
|
||||
import Control.Lens.TH (makePrisms)
|
||||
import Data.Kind (Type)
|
||||
|
||||
import Hasura.RQL.IR.BoolExp
|
||||
@ -47,7 +49,7 @@ data AnnInsert (b :: BackendType) (r :: BackendType -> Type) v
|
||||
|
||||
data AnnIns (b :: BackendType) (f :: Type -> Type) (v :: Type)
|
||||
= AnnIns
|
||||
{ _aiInsObj :: !(f (AnnInsObj b v))
|
||||
{ _aiInsObj :: !(f (AnnotatedInsertRow b v))
|
||||
, _aiTableName :: !(TableName b)
|
||||
, _aiConflictClause :: !(Maybe (ConflictClauseP1 b v))
|
||||
, _aiCheckCond :: !(AnnBoolExp b v, Maybe (AnnBoolExp b v))
|
||||
@ -67,24 +69,19 @@ newtype Single a = Single { unSingle :: a }
|
||||
type SingleObjIns b v = AnnIns b Single v
|
||||
type MultiObjIns b v = AnnIns b [] v
|
||||
|
||||
-- | An insert item.
|
||||
-- The object and array relationships are not unavailable when 'XNestedInserts b = XDisable'
|
||||
|
||||
data AnnotatedInsert (b :: BackendType) v
|
||||
= AIColumn !(Column b, v)
|
||||
| AIObjectRelationship !(XNestedInserts b) !(ObjRelIns b v)
|
||||
| AIArrayRelationship !(XNestedInserts b) !(ArrRelIns b v)
|
||||
deriving (Functor, Foldable, Traversable)
|
||||
|
||||
-- | One individual row to be inserted.
|
||||
-- Contains the columns' values and all the matching recursive relationship inserts.
|
||||
|
||||
data AnnInsObj (b :: BackendType) v
|
||||
= AnnInsObj
|
||||
{ _aioColumns :: ![(Column b, v)]
|
||||
, _aioObjRels :: ![ObjRelIns b v]
|
||||
, _aioArrRels :: ![ArrRelIns b v]
|
||||
} deriving (Functor, Foldable, Traversable)
|
||||
|
||||
instance Semigroup (AnnInsObj backend v) where
|
||||
(AnnInsObj col1 obj1 rel1) <> (AnnInsObj col2 obj2 rel2) =
|
||||
AnnInsObj (col1 <> col2) (obj1 <> obj2) (rel1 <> rel2)
|
||||
|
||||
instance Monoid (AnnInsObj backend v) where
|
||||
mempty = AnnInsObj [] [] []
|
||||
|
||||
type AnnotatedInsertRow b v = [AnnotatedInsert b v]
|
||||
|
||||
-- | One individual relationship.
|
||||
-- Unlike other types, this one is not parameterized by the type of the leaves
|
||||
@ -142,3 +139,15 @@ data InsertQueryP1 (b :: BackendType)
|
||||
, iqp1Output :: !(MutationOutput b)
|
||||
, iqp1AllCols :: ![ColumnInfo b]
|
||||
}
|
||||
|
||||
-- Template Haskell related
|
||||
$(makePrisms ''AnnotatedInsert)
|
||||
|
||||
getInsertColumns :: AnnotatedInsertRow b v -> [(Column b, v)]
|
||||
getInsertColumns = mapMaybe (^? _AIColumn)
|
||||
|
||||
getInsertObjectRelationships :: AnnotatedInsertRow b v -> [ObjRelIns b v]
|
||||
getInsertObjectRelationships = mapMaybe (fmap snd . (^? _AIObjectRelationship))
|
||||
|
||||
getInsertArrayRelationships :: AnnotatedInsertRow b v -> [ArrRelIns b v]
|
||||
getInsertArrayRelationships = mapMaybe (fmap snd . (^? _AIArrayRelationship))
|
||||
|
@ -120,6 +120,9 @@ class
|
||||
type XRelay b :: Type
|
||||
type XNodesAgg b :: Type
|
||||
|
||||
-- | Extension to flag the availability of object and array relationships in inserts (aka nested inserts).
|
||||
type XNestedInserts b :: Type
|
||||
|
||||
-- functions on types
|
||||
functionArgScalarType :: FunctionArgType b -> ScalarType b
|
||||
isComparableType :: ScalarType b -> Bool
|
||||
|
@ -13,6 +13,9 @@ module Hasura.RQL.Types.Column
|
||||
|
||||
, ColumnValue(..)
|
||||
|
||||
, IsIdentityColumn(..)
|
||||
, notIdentityColumn
|
||||
|
||||
, ColumnInfo(..)
|
||||
, RawColumnInfo(..)
|
||||
, PrimaryKeyColumns
|
||||
@ -145,6 +148,14 @@ parseScalarValuesColumnType
|
||||
parseScalarValuesColumnType columnType =
|
||||
indexedMapM (parseScalarValueColumnType columnType)
|
||||
|
||||
-- | Identity columns are table fields whose values are generated by the database. Refer https://en.wikipedia.org/wiki/Identity_column.
|
||||
newtype IsIdentityColumn
|
||||
= IsIdentityColumn { isIdentityColumn :: Bool}
|
||||
deriving (Generic, Eq, Show, ToJSON, FromJSON, NFData, Cacheable, Hashable)
|
||||
|
||||
notIdentityColumn :: IsIdentityColumn
|
||||
notIdentityColumn = IsIdentityColumn False
|
||||
|
||||
-- | “Raw” column info, as stored in the catalog (but not in the schema cache). Instead of
|
||||
-- containing a 'PGColumnType', it only contains a 'PGScalarType', which is combined with the
|
||||
-- 'pcirReferences' field and other table data to eventually resolve the type to a 'PGColumnType'.
|
||||
@ -157,6 +168,7 @@ data RawColumnInfo (b :: BackendType)
|
||||
-- consistently identified by its position.
|
||||
, prciType :: !(ScalarType b)
|
||||
, prciIsNullable :: !Bool
|
||||
, prciIsIdentity :: !IsIdentityColumn
|
||||
, prciDescription :: !(Maybe G.Description)
|
||||
} deriving (Generic)
|
||||
deriving instance Backend b => Eq (RawColumnInfo b)
|
||||
@ -178,6 +190,7 @@ data ColumnInfo (b :: BackendType)
|
||||
, pgiPosition :: !Int
|
||||
, pgiType :: !(ColumnType b)
|
||||
, pgiIsNullable :: !Bool
|
||||
, pgiIsIdentity :: !IsIdentityColumn
|
||||
, pgiDescription :: !(Maybe G.Description)
|
||||
} deriving (Generic)
|
||||
deriving instance Backend b => Eq (ColumnInfo b)
|
||||
|
@ -47,6 +47,7 @@ LEFT JOIN LATERAL
|
||||
'position', "column".attnum,
|
||||
'type', coalesce(base_type.typname, "type".typname),
|
||||
'is_nullable', NOT "column".attnotnull,
|
||||
'is_identity', coalesce(("info_column".is_identity::boolean), false),
|
||||
'description', pg_catalog.col_description("table".oid, "column".attnum)
|
||||
)) AS info
|
||||
FROM pg_catalog.pg_attribute "column"
|
||||
@ -54,6 +55,10 @@ LEFT JOIN LATERAL
|
||||
ON "type".oid = "column".atttypid
|
||||
LEFT JOIN pg_catalog.pg_type base_type
|
||||
ON "type".typtype = 'd' AND base_type.oid = "type".typbasetype
|
||||
LEFT JOIN information_schema.columns "info_column"
|
||||
ON "info_column".column_name = "column".attname
|
||||
AND "info_column".table_name = "table".relname
|
||||
AND "info_column".table_schema = "schema".nspname
|
||||
WHERE "column".attrelid = "table".oid
|
||||
-- columns where attnum <= 0 are special, system-defined columns
|
||||
AND "column".attnum > 0
|
||||
|
@ -4,7 +4,7 @@ SELECT ISNULL(
|
||||
JSON_QUERY([schema].json) AS [joined_sys_schema],
|
||||
JSON_QUERY([column].json) AS [joined_sys_column]
|
||||
FROM sys.objects object
|
||||
CROSS APPLY (SELECT [column].name, [column].column_id, [column].is_nullable, [column].user_type_id,
|
||||
CROSS APPLY (SELECT [column].name, [column].column_id, [column].is_nullable, [column].is_identity, [column].user_type_id,
|
||||
JSON_QUERY([types].json) AS [joined_sys_type],
|
||||
JSON_QUERY(ISNULL([relationships].json,'[]')) AS [joined_foreign_key_columns]
|
||||
FROM sys.columns [column]
|
||||
|
@ -37,6 +37,7 @@ LEFT JOIN LATERAL
|
||||
'position', "column".attnum,
|
||||
'type', coalesce(base_type.typname, "type".typname),
|
||||
'is_nullable', NOT "column".attnotnull,
|
||||
'is_identity', coalesce(("info_column".is_identity::boolean), false),
|
||||
'description', pg_catalog.col_description("table".oid, "column".attnum)
|
||||
)) AS info
|
||||
FROM pg_catalog.pg_attribute "column"
|
||||
@ -44,6 +45,10 @@ LEFT JOIN LATERAL
|
||||
ON "type".oid = "column".atttypid
|
||||
LEFT JOIN pg_catalog.pg_type base_type
|
||||
ON "type".typtype = 'd' AND base_type.oid = "type".typbasetype
|
||||
LEFT JOIN information_schema.columns "info_column"
|
||||
ON "info_column".column_name = "column".attname
|
||||
AND "info_column".table_name = "table".relname
|
||||
AND "info_column".table_schema = "schema".nspname
|
||||
WHERE "column".attrelid = "table".oid
|
||||
-- columns where attnum <= 0 are special, system-defined columns
|
||||
AND "column".attnum > 0
|
||||
|
Loading…
Reference in New Issue
Block a user