mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-09-11 02:35:32 +03:00
Fixed filtering not being applied across object relations in SQLite agent
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6937 GitOrigin-RevId: 655e9be98059a1e86566b975ae646b49d67fa06e
This commit is contained in:
parent
7228d0327f
commit
7e9f5bdd96
@ -294,7 +294,7 @@ type RelationshipJoinInfo = {
|
||||
columnMapping: Record<string, string> // Mapping from source table column name to target table column name
|
||||
}
|
||||
|
||||
function array_relationship(
|
||||
function table_query(
|
||||
ts: TableRelationships[],
|
||||
tableName: TableName,
|
||||
joinInfo: RelationshipJoinInfo | null,
|
||||
@ -325,20 +325,7 @@ function array_relationship(
|
||||
}
|
||||
})()
|
||||
|
||||
return tag('array_relationship',`(SELECT JSON_OBJECT(${[...fieldSelect, ...aggregateSelect].join(', ')}) ${fieldFrom})`);
|
||||
}
|
||||
|
||||
function object_relationship(
|
||||
ts: TableRelationships[],
|
||||
targetTable: TableName,
|
||||
joinInfo: RelationshipJoinInfo,
|
||||
fields: Fields,
|
||||
): string {
|
||||
const targetTableAlias = generateTableAlias(targetTable);
|
||||
const innerFrom = `${escapeTableName(targetTable)} AS ${targetTableAlias}`;
|
||||
const whereClause = where(ts, null, joinInfo, targetTable, targetTableAlias);
|
||||
return tag('object_relationship',
|
||||
`(SELECT JSON_OBJECT('rows', JSON_ARRAY(${json_object(ts, fields, targetTable, targetTableAlias)})) AS j FROM ${innerFrom} ${whereClause})`);
|
||||
return tag('table_query',`(SELECT JSON_OBJECT(${[...fieldSelect, ...aggregateSelect].join(', ')}) ${fieldFrom})`);
|
||||
}
|
||||
|
||||
function relationship(ts: TableRelationships[], r: Relationship, field: RelationshipField, sourceTableAlias: string): string {
|
||||
@ -348,28 +335,24 @@ function relationship(ts: TableRelationships[], r: Relationship, field: Relation
|
||||
columnMapping: r.column_mapping,
|
||||
};
|
||||
|
||||
switch(r.relationship_type) {
|
||||
case 'object':
|
||||
return tag('relationship', object_relationship(
|
||||
ts,
|
||||
r.target_table,
|
||||
relationshipJoinInfo,
|
||||
coerceUndefinedOrNullToEmptyRecord(field.query.fields),
|
||||
));
|
||||
// We force a limit of 1 for object relationships in case the user has configured a manual
|
||||
// "object" relationship that accidentally actually is an array relationship
|
||||
const limit =
|
||||
r.relationship_type === "object"
|
||||
? 1
|
||||
: coerceUndefinedToNull(field.query.limit);
|
||||
|
||||
case 'array':
|
||||
return tag('relationship', array_relationship(
|
||||
ts,
|
||||
r.target_table,
|
||||
relationshipJoinInfo,
|
||||
coerceUndefinedOrNullToEmptyRecord(field.query.fields),
|
||||
coerceUndefinedOrNullToEmptyRecord(field.query.aggregates),
|
||||
coerceUndefinedToNull(field.query.where),
|
||||
coerceUndefinedToNull(field.query.limit),
|
||||
coerceUndefinedToNull(field.query.offset),
|
||||
coerceUndefinedToNull(field.query.order_by),
|
||||
));
|
||||
}
|
||||
return tag("relationship", table_query(
|
||||
ts,
|
||||
r.target_table,
|
||||
relationshipJoinInfo,
|
||||
coerceUndefinedOrNullToEmptyRecord(field.query.fields),
|
||||
coerceUndefinedOrNullToEmptyRecord(field.query.aggregates),
|
||||
coerceUndefinedToNull(field.query.where),
|
||||
limit,
|
||||
coerceUndefinedToNull(field.query.offset),
|
||||
coerceUndefinedToNull(field.query.order_by),
|
||||
));
|
||||
}
|
||||
|
||||
function bop_array(o: BinaryArrayComparisonOperator): string {
|
||||
@ -625,7 +608,7 @@ function offset(o: number | null): string {
|
||||
/** Top-Level Query Function.
|
||||
*/
|
||||
function query(request: QueryRequest): string {
|
||||
const result = array_relationship(
|
||||
const result = table_query(
|
||||
request.table_relationships,
|
||||
request.table,
|
||||
null,
|
||||
|
@ -3,11 +3,12 @@ module Test.QuerySpec.RelationshipsSpec (spec) where
|
||||
import Control.Arrow ((>>>))
|
||||
import Control.Lens (Traversal', ix, (&), (?~), (^.), (^..), (^?), _Just)
|
||||
import Control.Monad (when)
|
||||
import Data.Aeson (Value (..))
|
||||
import Data.HashMap.Strict (HashMap)
|
||||
import Data.List (sortOn)
|
||||
import Data.List.NonEmpty (NonEmpty (..))
|
||||
import Data.List.NonEmpty qualified as NonEmpty
|
||||
import Data.Maybe (maybeToList)
|
||||
import Data.Maybe (fromMaybe, maybeToList)
|
||||
import Hasura.Backends.DataConnector.API
|
||||
import Servant.API (NamedRoutes)
|
||||
import Servant.Client (Client)
|
||||
@ -65,6 +66,43 @@ spec TestData {..} api sourceName config subqueryComparisonCapabilities = descri
|
||||
Data.responseRows receivedArtists `rowsShouldBe` expectedAlbums
|
||||
_qrAggregates receivedArtists `jsonShouldBe` Nothing
|
||||
|
||||
it "can filter in object relationships" $ do
|
||||
let artistWhere = ApplyBinaryComparisonOperator GreaterThanOrEqual (_tdCurrentComparisonColumn "Name" _tdStringType) (ScalarValue (String "H") _tdStringType)
|
||||
let query = albumsWithArtistQuery (qWhere ?~ artistWhere)
|
||||
receivedAlbums <- Data.sortResponseRowsBy "AlbumId" <$> guardedQuery api sourceName config query
|
||||
|
||||
let joinInArtist (album :: HashMap FieldName FieldValue) =
|
||||
let artist = do
|
||||
artistId <- album ^? Data.field "ArtistId" . Data._ColumnFieldNumber
|
||||
artist' <- _tdArtistsRowsById ^? ix artistId
|
||||
if (artist' ^? Data.field "Name" . Data._ColumnFieldString) >= Just "H" then Just artist' else Nothing
|
||||
artistPropVal = maybeToList artist
|
||||
in Data.insertField "Artist" (mkSubqueryResponse artistPropVal) album
|
||||
let removeArtistId = Data.deleteField "ArtistId"
|
||||
|
||||
let expectedAlbums = (removeArtistId . joinInArtist) <$> _tdAlbumsRows
|
||||
Data.responseRows receivedAlbums `rowsShouldBe` expectedAlbums
|
||||
_qrAggregates receivedAlbums `jsonShouldBe` Nothing
|
||||
|
||||
it "can filter in array relationships" $ do
|
||||
let albumsWhere = ApplyBinaryComparisonOperator GreaterThanOrEqual (_tdCurrentComparisonColumn "Title" _tdStringType) (ScalarValue (String "O") _tdStringType)
|
||||
let query = artistsWithAlbumsQuery (qWhere ?~ albumsWhere)
|
||||
receivedArtists <- Data.sortResponseRowsBy "ArtistId" <$> guardedQuery api sourceName config query
|
||||
|
||||
let joinInAlbums (artist :: HashMap FieldName FieldValue) =
|
||||
let albums = fromMaybe [] $ do
|
||||
artistId <- artist ^? Data.field "ArtistId" . Data._ColumnFieldNumber
|
||||
_tdAlbumsRows
|
||||
& filter (\album -> album ^? Data.field "ArtistId" . Data._ColumnFieldNumber == Just artistId && album ^? Data.field "Title" . Data._ColumnFieldString >= Just "O")
|
||||
& fmap (Data.deleteField "ArtistId")
|
||||
& sortOn (^? Data.field "ArtistId")
|
||||
& pure
|
||||
in Data.insertField "Albums" (mkSubqueryResponse albums) artist
|
||||
|
||||
let expectedAlbums = joinInAlbums <$> _tdArtistsRows
|
||||
Data.responseRows receivedArtists `rowsShouldBe` expectedAlbums
|
||||
_qrAggregates receivedArtists `jsonShouldBe` Nothing
|
||||
|
||||
when ((_ctccSupportsRelations <$> subqueryComparisonCapabilities) == Just True) $
|
||||
describe "Cross related table comparisons" $ do
|
||||
it "perform an object relationship query by joining employee to customers and filter comparing columns across the object relationship" $ do
|
||||
|
Loading…
Reference in New Issue
Block a user