mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 17:31:56 +03:00
chore(server): allow non-nullable NQ -> NQ object relationships
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9353 GitOrigin-RevId: 9da95675d224f3045509592c2515b7afa2500d00
This commit is contained in:
parent
b19eff22e9
commit
7d011644ac
@ -204,6 +204,7 @@ fromRemoteRelationFieldsG existingJoins joinColumns (IR.FieldName name, field) =
|
||||
IR.AnnRelationSelectG
|
||||
(IR.RelName $ mkNonEmptyTextUnsafe name)
|
||||
joinColumns
|
||||
IR.Nullable
|
||||
annotatedRelationship
|
||||
|
||||
-- | Top/root-level 'Select'. All descendent/sub-translations are collected to produce a root TSQL.Select.
|
||||
|
@ -31,6 +31,7 @@ import Hasura.Backends.Postgres.Translate.Select.Internal.Helpers
|
||||
import Hasura.Backends.Postgres.Translate.Types
|
||||
import Hasura.Prelude
|
||||
import Hasura.RQL.IR.Select (ConnectionSlice (SliceFirst, SliceLast))
|
||||
import Hasura.RQL.Types.Relationships.Local (Nullable (..))
|
||||
|
||||
generateSQLSelect ::
|
||||
-- | Pre join condition for lateral joins
|
||||
@ -86,9 +87,9 @@ generateSQLSelect joinCondition selectSource selectNode =
|
||||
S.WhereFrag $ S.simplifyBoolExp $ S.BEBin S.AndOp joinCond whereCond
|
||||
|
||||
-- function to create a joined from item from two from items
|
||||
leftOuterJoin current new =
|
||||
leftOuterJoin current (new, joinType) =
|
||||
S.FIJoin
|
||||
$ S.JoinExpr current S.LeftOuter new
|
||||
$ S.JoinExpr current joinType new
|
||||
$ S.JoinOn
|
||||
$ S.BELit True
|
||||
|
||||
@ -102,33 +103,40 @@ generateSQLSelect joinCondition selectSource selectNode =
|
||||
<> map computedFieldToFromItem (HashMap.toList computedFields)
|
||||
|
||||
objectRelationToFromItem ::
|
||||
(ObjectRelationSource, SelectNode) -> S.FromItem
|
||||
(ObjectRelationSource, SelectNode) -> (S.FromItem, S.JoinType)
|
||||
objectRelationToFromItem (objectRelationSource, node) =
|
||||
let ObjectRelationSource _ colMapping objectSelectSource = objectRelationSource
|
||||
let ObjectRelationSource
|
||||
{ _orsRelationMapping = colMapping,
|
||||
_orsSelectSource = objectSelectSource,
|
||||
_orsNullable = nullable
|
||||
} = objectRelationSource
|
||||
alias = S.toTableAlias $ _ossPrefix objectSelectSource
|
||||
source = objectSelectSourceToSelectSource objectSelectSource
|
||||
select = generateSQLSelect (mkJoinCond baseSelectIdentifier colMapping) source node
|
||||
in S.mkLateralFromItem select alias
|
||||
joinType = case nullable of
|
||||
Nullable -> S.LeftOuter
|
||||
NotNullable -> S.Inner
|
||||
in (S.mkLateralFromItem select alias, joinType)
|
||||
|
||||
arrayRelationToFromItem ::
|
||||
(ArrayRelationSource, MultiRowSelectNode) -> S.FromItem
|
||||
(ArrayRelationSource, MultiRowSelectNode) -> (S.FromItem, S.JoinType)
|
||||
arrayRelationToFromItem (arrayRelationSource, arraySelectNode) =
|
||||
let ArrayRelationSource _ colMapping source = arrayRelationSource
|
||||
alias = S.toTableAlias $ _ssPrefix source
|
||||
select =
|
||||
generateSQLSelectFromArrayNode source arraySelectNode
|
||||
$ mkJoinCond baseSelectIdentifier colMapping
|
||||
in S.mkLateralFromItem select alias
|
||||
in (S.mkLateralFromItem select alias, S.LeftOuter)
|
||||
|
||||
arrayConnectionToFromItem ::
|
||||
(ArrayConnectionSource, MultiRowSelectNode) -> S.FromItem
|
||||
(ArrayConnectionSource, MultiRowSelectNode) -> (S.FromItem, S.JoinType)
|
||||
arrayConnectionToFromItem (arrayConnectionSource, arraySelectNode) =
|
||||
let selectWith = connectionToSelectWith baseSelectAlias arrayConnectionSource arraySelectNode
|
||||
alias = S.toTableAlias $ _ssPrefix $ _acsSource arrayConnectionSource
|
||||
in S.FISelectWith (S.Lateral True) selectWith alias
|
||||
in (S.FISelectWith (S.Lateral True) selectWith alias, S.LeftOuter)
|
||||
|
||||
computedFieldToFromItem ::
|
||||
(ComputedFieldTableSetSource, MultiRowSelectNode) -> S.FromItem
|
||||
(ComputedFieldTableSetSource, MultiRowSelectNode) -> (S.FromItem, S.JoinType)
|
||||
computedFieldToFromItem (computedFieldTableSource, node) =
|
||||
let ComputedFieldTableSetSource _ source = computedFieldTableSource
|
||||
internalSelect = generateSQLSelect (S.BELit True) source $ _mrsnSelectNode node
|
||||
@ -138,7 +146,7 @@ generateSQLSelect joinCondition selectSource selectNode =
|
||||
{ S.selExtr = _mrsnTopExtractors node,
|
||||
S.selFrom = Just $ S.FromExp [S.mkSelFromItem internalSelect alias]
|
||||
}
|
||||
in S.mkLateralFromItem select alias
|
||||
in (S.mkLateralFromItem select alias, S.LeftOuter)
|
||||
|
||||
-- | Create a select query
|
||||
generateSQLSelectFromArrayNode ::
|
||||
|
@ -130,7 +130,7 @@ processOrderByItems sourcePrefix' fieldAlias' similarArrayFields distOnCols = \c
|
||||
(tableIdentifierToIdentifier relSourcePrefix)
|
||||
(S.FISimple relTable Nothing)
|
||||
(toSQLBoolExp (S.QualTable relTable) relFilter)
|
||||
relSource = ObjectRelationSource relName colMapping selectSource
|
||||
relSource = ObjectRelationSource relName colMapping selectSource Nullable
|
||||
pure
|
||||
( relSource,
|
||||
HashMap.singleton relOrderByAlias relOrdByExp,
|
||||
|
@ -291,7 +291,7 @@ processAnnFields sourcePrefix fieldAlias similarArrFields annFields tCase = do
|
||||
AFNodeId _ sn tn pKeys -> pure $ mkNodeId sn tn pKeys
|
||||
AFColumn c -> toSQLCol c
|
||||
AFObjectRelation objSel -> withWriteObjectRelation $ do
|
||||
let AnnRelationSelectG relName relMapping annObjSel = objSel
|
||||
let AnnRelationSelectG relName relMapping nullable annObjSel = objSel
|
||||
AnnObjectSelectG objAnnFields target targetFilter = annObjSel
|
||||
objRelSourcePrefix = mkObjectRelationTableAlias sourcePrefix relName
|
||||
sourcePrefixes = mkSourcePrefixes objRelSourcePrefix
|
||||
@ -314,7 +314,7 @@ processAnnFields sourcePrefix fieldAlias similarArrFields annFields tCase = do
|
||||
(_pfThis sourcePrefixes)
|
||||
(S.FIIdentifier nativeQueryIdentifier)
|
||||
(toSQLBoolExp (S.QualifiedIdentifier nativeQueryIdentifier Nothing) targetFilter)
|
||||
objRelSource = ObjectRelationSource relName relMapping selectSource
|
||||
objRelSource = ObjectRelationSource relName relMapping selectSource nullable
|
||||
pure
|
||||
( objRelSource,
|
||||
HashMap.fromList [annFieldsExtr],
|
||||
@ -326,7 +326,7 @@ processAnnFields sourcePrefix fieldAlias similarArrFields annFields tCase = do
|
||||
(_pfThis sourcePrefixes)
|
||||
(S.FISimple tableFrom Nothing)
|
||||
(toSQLBoolExp (S.QualTable tableFrom) targetFilter)
|
||||
objRelSource = ObjectRelationSource relName relMapping selectSource
|
||||
objRelSource = ObjectRelationSource relName relMapping selectSource Nullable
|
||||
pure
|
||||
( objRelSource,
|
||||
HashMap.fromList [annFieldsExtr],
|
||||
@ -496,7 +496,7 @@ processArrayRelation ::
|
||||
processArrayRelation sourcePrefixes fieldAlias relAlias arrSel _tCase =
|
||||
case arrSel of
|
||||
ASSimple annArrRel -> withWriteArrayRelation $ do
|
||||
let AnnRelationSelectG _ colMapping sel = annArrRel
|
||||
let AnnRelationSelectG _ colMapping _ sel = annArrRel
|
||||
permLimitSubQuery =
|
||||
maybe PLSQNotRequired PLSQRequired $ _tpLimit $ _asnPerm sel
|
||||
(source, nodeExtractors) <-
|
||||
@ -514,7 +514,7 @@ processArrayRelation sourcePrefixes fieldAlias relAlias arrSel _tCase =
|
||||
()
|
||||
)
|
||||
ASAggregate aggSel -> withWriteArrayRelation $ do
|
||||
let AnnRelationSelectG _ colMapping sel = aggSel
|
||||
let AnnRelationSelectG _ colMapping _ sel = aggSel
|
||||
(source, nodeExtractors, topExtr) <-
|
||||
processAnnAggregateSelect sourcePrefixes fieldAlias sel
|
||||
pure
|
||||
@ -524,7 +524,7 @@ processArrayRelation sourcePrefixes fieldAlias relAlias arrSel _tCase =
|
||||
()
|
||||
)
|
||||
ASConnection connSel -> withWriteArrayConnection $ do
|
||||
let AnnRelationSelectG _ colMapping sel = connSel
|
||||
let AnnRelationSelectG _ colMapping _ sel = connSel
|
||||
(source, topExtractor, nodeExtractors) <-
|
||||
processConnectionSelect sourcePrefixes fieldAlias relAlias colMapping sel
|
||||
pure
|
||||
|
@ -12,7 +12,7 @@ module Hasura.Backends.Postgres.Translate.Types
|
||||
DistinctAndOrderByExpr (ASorting),
|
||||
JoinTree (..),
|
||||
MultiRowSelectNode (..),
|
||||
ObjectRelationSource (ObjectRelationSource),
|
||||
ObjectRelationSource (..),
|
||||
ObjectSelectSource (ObjectSelectSource, _ossPrefix),
|
||||
PermissionLimitSubQuery (..),
|
||||
SelectNode (SelectNode),
|
||||
@ -38,6 +38,7 @@ import Hasura.NativeQuery.Metadata (InterpolatedQuery)
|
||||
import Hasura.Prelude
|
||||
import Hasura.RQL.IR.Select
|
||||
import Hasura.RQL.Types.Common
|
||||
import Hasura.RQL.Types.Relationships.Local (Nullable)
|
||||
|
||||
data SourcePrefixes = SourcePrefixes
|
||||
{ -- | Current source prefix
|
||||
@ -169,7 +170,8 @@ objectSelectSourceToSelectSource ObjectSelectSource {..} =
|
||||
data ObjectRelationSource = ObjectRelationSource
|
||||
{ _orsRelationshipName :: RelName,
|
||||
_orsRelationMapping :: HashMap.HashMap Postgres.PGCol Postgres.PGCol,
|
||||
_orsSelectSource :: ObjectSelectSource
|
||||
_orsSelectSource :: ObjectSelectSource,
|
||||
_orsNullable :: Nullable
|
||||
}
|
||||
deriving (Generic, Show)
|
||||
|
||||
|
@ -33,6 +33,7 @@ import Hasura.RQL.Types.Backend
|
||||
import Hasura.RQL.Types.BackendType
|
||||
import Hasura.RQL.Types.Column (ColumnType, fromCol)
|
||||
import Hasura.RQL.Types.Common
|
||||
import Hasura.RQL.Types.Relationships.Local (Nullable (..))
|
||||
import Hasura.RQL.Types.ResultCustomization
|
||||
import Hasura.RQL.Types.Schema.Options qualified as Options
|
||||
import Hasura.RemoteSchema.SchemaCache
|
||||
@ -197,11 +198,11 @@ convertRemoteSourceRelationship
|
||||
|
||||
relationshipField = case relationship of
|
||||
SourceRelationshipObject s ->
|
||||
AFObjectRelation $ AnnRelationSelectG relName columnMapping s
|
||||
AFObjectRelation $ AnnRelationSelectG relName columnMapping Nullable s
|
||||
SourceRelationshipArray s ->
|
||||
AFArrayRelation $ ASSimple $ AnnRelationSelectG relName columnMapping s
|
||||
AFArrayRelation $ ASSimple $ AnnRelationSelectG relName columnMapping Nullable s
|
||||
SourceRelationshipArrayAggregate s ->
|
||||
AFArrayRelation $ ASAggregate $ AnnRelationSelectG relName columnMapping s
|
||||
AFArrayRelation $ ASAggregate $ AnnRelationSelectG relName columnMapping Nullable s
|
||||
|
||||
argumentIdField =
|
||||
( fromCol @b argumentIdColumn,
|
||||
|
@ -1448,7 +1448,7 @@ relationshipField table ri = runMaybeT do
|
||||
$ P.subselection_ relFieldName desc selectionSetParser
|
||||
<&> \fields ->
|
||||
IR.AFObjectRelation
|
||||
$ IR.AnnRelationSelectG (riName ri) (riMapping ri)
|
||||
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable
|
||||
$ IR.AnnObjectSelectG fields (IR.FromTable otherTableName)
|
||||
$ deduplicatePermissions
|
||||
$ IR._tpFilter
|
||||
@ -1460,7 +1460,7 @@ relationshipField table ri = runMaybeT do
|
||||
otherTableParser <&> \selectExp ->
|
||||
IR.AFArrayRelation
|
||||
$ IR.ASSimple
|
||||
$ IR.AnnRelationSelectG (riName ri) (riMapping ri)
|
||||
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) Nullable
|
||||
$ deduplicatePermissions' selectExp
|
||||
relAggFieldName = applyFieldNameCaseCust tCase $ relFieldName <> Name.__aggregate
|
||||
relAggDesc = Just $ G.Description "An aggregate relationship"
|
||||
@ -1479,8 +1479,8 @@ relationshipField table ri = runMaybeT do
|
||||
pure
|
||||
$ catMaybes
|
||||
[ Just arrayRelField,
|
||||
fmap (IR.AFArrayRelation . IR.ASAggregate . IR.AnnRelationSelectG (riName ri) (riMapping ri)) <$> remoteAggField,
|
||||
fmap (IR.AFArrayRelation . IR.ASConnection . IR.AnnRelationSelectG (riName ri) (riMapping ri)) <$> remoteConnectionField
|
||||
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
|
||||
]
|
||||
|
||||
tablePermissionsInfo :: (Backend b) => SelPermInfo b -> TablePerms b
|
||||
|
@ -200,11 +200,11 @@ parseLogicalModelField relationshipInfo column logimoField = do
|
||||
( LogicalModelField
|
||||
{ lmfType =
|
||||
LogicalModelTypeReference
|
||||
(LogicalModelTypeReferenceC {lmtrReference})
|
||||
(LogicalModelTypeReferenceC {lmtrNullable, lmtrReference})
|
||||
}
|
||||
) -> do
|
||||
-- we currently ignore nullability and assume the field is nullable
|
||||
relName <- hoistMaybe $ columnToRelName @b column
|
||||
|
||||
-- lookup the reference in the data source
|
||||
relationship <-
|
||||
InsOrdHashMap.lookup relName relationshipInfo
|
||||
@ -215,14 +215,14 @@ parseLogicalModelField relationshipInfo column logimoField = do
|
||||
<> commaSeparated (map relNameToTxt (InsOrdHashMap.keys relationshipInfo))
|
||||
<> "]."
|
||||
)
|
||||
logicalModelObjectRelationshipField @b @r @m @n lmtrReference relationship
|
||||
logicalModelObjectRelationshipField @b @r @m @n lmtrReference (nullableFromBool lmtrNullable) relationship
|
||||
( LogicalModelField
|
||||
{ lmfType =
|
||||
LogicalModelTypeArray
|
||||
( LogicalModelTypeArrayC
|
||||
{ lmtaArray =
|
||||
LogicalModelTypeReference (LogicalModelTypeReferenceC {lmtrReference}),
|
||||
lmtaNullable
|
||||
LogicalModelTypeReference (LogicalModelTypeReferenceC {lmtrReference, lmtrNullable = innerNullability}),
|
||||
lmtaNullable = arrayNullability
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -232,9 +232,12 @@ parseLogicalModelField relationshipInfo column logimoField = do
|
||||
relName <- hoistMaybe $ columnToRelName @b column
|
||||
-- lookup the reference in the data source
|
||||
relationship <- hoistMaybe $ InsOrdHashMap.lookup relName relationshipInfo
|
||||
let nullability = if lmtaNullable then Nullable else NotNullable
|
||||
|
||||
logicalModelArrayRelationshipField @b @r @m @n lmtrReference nullability relationship
|
||||
logicalModelArrayRelationshipField @b @r @m @n
|
||||
lmtrReference
|
||||
(nullableFromBool arrayNullability)
|
||||
(nullableFromBool innerNullability)
|
||||
relationship
|
||||
( LogicalModelField
|
||||
{ lmfType =
|
||||
LogicalModelTypeArray
|
||||
@ -250,6 +253,10 @@ parseLogicalModelField relationshipInfo column logimoField = do
|
||||
) ->
|
||||
throw500 "Nested arrays are not currently implemented"
|
||||
|
||||
nullableFromBool :: Bool -> Nullable
|
||||
nullableFromBool True = Nullable
|
||||
nullableFromBool False = NotNullable
|
||||
|
||||
defaultLogicalModelSelectionSet ::
|
||||
forall b r m n.
|
||||
( MonadBuildSchema b r m n,
|
||||
@ -421,9 +428,10 @@ logicalModelObjectRelationshipField ::
|
||||
MonadBuildSchema b r m n
|
||||
) =>
|
||||
LogicalModelName ->
|
||||
Nullable ->
|
||||
RelInfo b ->
|
||||
MaybeT (SchemaT r m) (FieldParser n (AnnotatedField b))
|
||||
logicalModelObjectRelationshipField logicalModelName ri | riType ri == ObjRel =
|
||||
logicalModelObjectRelationshipField logicalModelName nullability ri | riType ri == ObjRel =
|
||||
case riTarget ri of
|
||||
RelTargetNativeQuery nativeQueryName -> do
|
||||
nativeQueryInfo <- lift $ askNativeQueryInfo nativeQueryName
|
||||
@ -443,16 +451,22 @@ logicalModelObjectRelationshipField logicalModelName ri | riType ri == ObjRel =
|
||||
relFieldName <- lift $ textToName $ relNameToTxt $ riName ri
|
||||
|
||||
let objectRelDesc = Just $ G.Description "An object relationship"
|
||||
|
||||
nativeQueryParser <- MaybeT $ selectNativeQueryObject nativeQueryInfo relFieldName objectRelDesc
|
||||
|
||||
-- this only affects the generated GraphQL type
|
||||
let nullabilityModifier =
|
||||
case nullability of
|
||||
Nullable -> id
|
||||
NotNullable -> IP.nonNullableField
|
||||
|
||||
pure
|
||||
$ nullabilityModifier
|
||||
$ nativeQueryParser
|
||||
<&> \selectExp ->
|
||||
IR.AFObjectRelation (IR.AnnRelationSelectG (riName ri) (riMapping ri) selectExp)
|
||||
IR.AFObjectRelation (IR.AnnRelationSelectG (riName ri) (riMapping ri) nullability selectExp)
|
||||
RelTargetTable _otherTableName -> do
|
||||
throw500 "Object relationships from logical models to tables are not implemented"
|
||||
logicalModelObjectRelationshipField _ _ =
|
||||
logicalModelObjectRelationshipField _ _ _ =
|
||||
hoistMaybe Nothing -- the target logical model expected an object relationship, but this was an array
|
||||
|
||||
-- | Field parsers for a logical model relationship
|
||||
@ -463,9 +477,10 @@ logicalModelArrayRelationshipField ::
|
||||
) =>
|
||||
LogicalModelName ->
|
||||
Nullable ->
|
||||
Nullable ->
|
||||
RelInfo b ->
|
||||
MaybeT (SchemaT r m) (FieldParser n (AnnotatedField b))
|
||||
logicalModelArrayRelationshipField logicalModelName nullability ri | riType ri == ArrRel =
|
||||
logicalModelArrayRelationshipField logicalModelName arrayNullability innerNullability ri | riType ri == ArrRel =
|
||||
case riTarget ri of
|
||||
RelTargetNativeQuery nativeQueryName -> do
|
||||
nativeQueryInfo <- lift $ askNativeQueryInfo nativeQueryName
|
||||
@ -485,15 +500,15 @@ logicalModelArrayRelationshipField logicalModelName nullability ri | riType ri =
|
||||
|
||||
let objectRelDesc = Just $ G.Description "An array relationship"
|
||||
|
||||
nativeQueryParser <- MaybeT $ selectNativeQuery nativeQueryInfo relFieldName nullability objectRelDesc
|
||||
nativeQueryParser <- MaybeT $ selectNativeQuery nativeQueryInfo relFieldName arrayNullability objectRelDesc
|
||||
|
||||
pure
|
||||
$ nativeQueryParser
|
||||
<&> \selectExp ->
|
||||
IR.AFArrayRelation
|
||||
$ IR.ASSimple
|
||||
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) selectExp
|
||||
$ IR.AnnRelationSelectG (riName ri) (riMapping ri) innerNullability selectExp
|
||||
RelTargetTable _otherTableName -> do
|
||||
throw500 "Array relationships from logical models to tables are not implemented"
|
||||
logicalModelArrayRelationshipField _ _ _ =
|
||||
logicalModelArrayRelationshipField _ _ _ _ =
|
||||
hoistMaybe Nothing -- the target logical model expected an array relationship, but this was an object
|
||||
|
@ -292,7 +292,7 @@ convExtRel sqlGen fieldInfoMap relName mAlias selQ sessVarBldr prepValBldr = do
|
||||
when misused $ throw400 UnexpectedPayload objRelMisuseMsg
|
||||
pure
|
||||
$ Left
|
||||
$ AnnRelationSelectG (fromMaybe relName mAlias) colMapping
|
||||
$ AnnRelationSelectG (fromMaybe relName mAlias) colMapping Nullable
|
||||
$ AnnObjectSelectG (_asnFields annSel) (FromTable relTableName)
|
||||
$ _tpFilter
|
||||
$ _asnPerm annSel
|
||||
@ -303,6 +303,7 @@ convExtRel sqlGen fieldInfoMap relName mAlias selQ sessVarBldr prepValBldr = do
|
||||
$ AnnRelationSelectG
|
||||
(fromMaybe relName mAlias)
|
||||
colMapping
|
||||
Nullable
|
||||
annSel
|
||||
where
|
||||
pgWhenRelErr = "only relationships can be expanded"
|
||||
|
@ -18,6 +18,7 @@ module Hasura.RQL.IR.Select.Lenses
|
||||
aarAnnSelect,
|
||||
aarColumnMapping,
|
||||
aarRelationshipName,
|
||||
aarNullable,
|
||||
anosSupportsNestedObjects,
|
||||
anosColumn,
|
||||
anosFields,
|
||||
|
@ -12,12 +12,14 @@ import Hasura.Prelude
|
||||
import Hasura.RQL.Types.Backend
|
||||
import Hasura.RQL.Types.BackendType
|
||||
import Hasura.RQL.Types.Common
|
||||
import Hasura.RQL.Types.Relationships.Local (Nullable)
|
||||
|
||||
-- Local relationship
|
||||
|
||||
data AnnRelationSelectG (b :: BackendType) a = AnnRelationSelectG
|
||||
{ _aarRelationshipName :: RelName, -- Relationship name
|
||||
_aarColumnMapping :: HashMap (Column b) (Column b), -- Column of left table to join with
|
||||
_aarNullable :: Nullable, -- is the target object allowed to be missing?
|
||||
_aarAnnSelect :: a -- Current table. Almost ~ to SQL Select
|
||||
}
|
||||
deriving stock (Functor, Foldable, Traversable)
|
||||
|
Loading…
Reference in New Issue
Block a user