Rework GraphQL schema and IR parsing for boolean expressions to fix issues with nested fields (#1361)

### What
This PR reworks the GraphQL schema annotation types and IR parsing for
boolean expressions. This was required because the existing code was
quite tangled and broken as it did not properly handled nested fields.
For example, it had the following issues:

* If you use more than one nested field in a single where, an invalid
NDC query is generated with mangled field paths
* If you use logical operators inside a nested field, an internal error
occurs

The new annotation structure and IR parsing code cleanly matches the two
types of boolean expressions we currently have: object boolean
expressions and scalar boolean expressions. The new parsing code
correctly tracks nested fields and allows arbitrary nesting of object
boolean expressions (and therefore logical operators at the object
boolean expression level).

### How

In `crates/graphql/schema/src/types.rs` `BooleanExpressionAnnotation`
has been reworked to capture the two different types of boolean
expressions. It now has the two `ObjectBooleanExpressionField` and
`ScalarBooleanExpressionField` variants, which are used to denote fields
on each of the different types of boolean expression objects. Previously
scalar boolean expression annotations lived on `ModelInputAnnotation`,
muddying the waters.

Then in `crates/graphql/ir/src/filter.rs`, we have
`resolve_object_boolean_expression` and
`resolve_scalar_boolean_expression` which are capable of reading the
respective variants of boolean expressions.
`resolve_object_boolean_expression` is recursive, and so nested logical
operators are handled naturally. As nested fields are descended through,
this is kept track of with `column_path`.

Some new fields were added to the existing nested object test
(`crates/engine/tests/execute/models/select_many/where/nested_select/object/request.gql`)
to capture and test the previously broken scenarios.

A minor fix was made to `crates/graphql/frontend/src/to_opendd_ir.rs`
because it did not handle multiple root fields properly, as it did not
use the root field aliases and ended up overwriting the same query over
and over. This resulted in many snapshots getting updated, even though
they are unrelated to the real change in this PR.

V3_GIT_ORIGIN_REV_ID: f7cbbe8c86f542150e0ce247c6597df717836c06
This commit is contained in:
Daniel Chambers 2024-11-21 10:16:16 +11:00 committed by hasura-bot
parent e6f56f8c1d
commit 9a913ea2c2
61 changed files with 7020 additions and 575 deletions

View File

@ -1,5 +1,5 @@
# This should match the Rust version in rust-toolchain.yaml and the other Dockerfiles.
FROM rust:1.82.0 as chef
FROM rust:1.82.0 AS chef
WORKDIR app

View File

@ -6,6 +6,11 @@
### Fixed
- Fixed an error that occurred when filtering by more than one nested field at a
time.
- Fixed an error that occurred when filtering using logical operators (eg
`_and`) from inside a nested field.
### Changed
## [v2024.11.18]

View File

@ -96,6 +96,10 @@
{
"fieldName": "staff",
"booleanExpressionType": "staff_bool_exp"
},
{
"fieldName": "songs",
"booleanExpressionType": "institution_songs_bool_exp"
}
],
"comparableRelationships": []
@ -112,6 +116,38 @@
}
}
},
{
"kind": "BooleanExpressionType",
"version": "v1",
"definition": {
"name": "institution_songs_bool_exp",
"operand": {
"object": {
"type": "institution_songs",
"comparableFields": [
{
"fieldName": "primaryAnthemTrackId",
"booleanExpressionType": "int_bool_exp"
},
{
"fieldName": "secondaryAnthemTrackId",
"booleanExpressionType": "int_bool_exp"
}
],
"comparableRelationships": []
}
},
"logicalOperators": {
"enable": true
},
"isNull": {
"enable": true
},
"graphql": {
"typeName": "InstitutionSongsBoolExp"
}
}
},
{
"kind": "BooleanExpressionType",
"version": "v1",
@ -209,6 +245,10 @@
{
"name": "departments",
"type": "[String]"
},
{
"name": "songs",
"type": "institution_songs"
}
],
"graphql": {
@ -243,6 +283,11 @@
"column": {
"name": "departments"
}
},
"songs": {
"column": {
"name": "songs"
}
}
}
}
@ -263,7 +308,64 @@
"name",
"location",
"staff",
"departments"
"departments",
"songs"
]
}
}
]
}
},
{
"kind": "ObjectType",
"version": "v1",
"definition": {
"name": "institution_songs",
"fields": [
{
"name": "primaryAnthemTrackId",
"type": "Int"
},
{
"name": "secondaryAnthemTrackId",
"type": "Int"
}
],
"graphql": {
"typeName": "InstitutionSongs"
},
"dataConnectorTypeMapping": [
{
"dataConnectorName": "db",
"dataConnectorObjectType": "institution_songs",
"fieldMapping": {
"primaryAnthemTrackId": {
"column": {
"name": "primary_anthem_track_id"
}
},
"secondaryAnthemTrackId": {
"column": {
"name": "secondary_anthem_track_id"
}
}
}
}
]
}
},
{
"kind": "TypePermissions",
"version": "v1",
"definition": {
"typeName": "institution_songs",
"permissions": [
{
"role": "admin",
"output": {
"allowedFields": [
"primaryAnthemTrackId",
"secondaryAnthemTrackId"
]
}
}
@ -627,6 +729,12 @@
"orderByDirections": {
"enableAll": true
}
},
{
"fieldName": "songs",
"orderByDirections": {
"enableAll": true
}
}
]
}

View File

@ -70,6 +70,31 @@
"Medicine and Dentistry"
]
}
],
"match_two_nested_fields": [
{
"id": 1,
"songs": {
"primaryAnthemTrackId": 2270,
"secondaryAnthemTrackId": 2271
}
}
],
"nested_logical_operators": [
{
"id": 1,
"songs": {
"primaryAnthemTrackId": 2270,
"secondaryAnthemTrackId": 2271
}
},
{
"id": 2,
"songs": {
"primaryAnthemTrackId": 3421,
"secondaryAnthemTrackId": null
}
}
]
}
},

View File

@ -44,4 +44,36 @@ query MyQuery {
}
departments
}
match_two_nested_fields: InstitutionMany(
where: {
songs: {
primaryAnthemTrackId: { _eq: 2270 }
secondaryAnthemTrackId: { _eq: 2271 }
}
}
) {
id
songs {
primaryAnthemTrackId
secondaryAnthemTrackId
}
}
nested_logical_operators: InstitutionMany(
where: {
songs: {
_or: [
{ primaryAnthemTrackId: { _eq: 2270 } }
{ primaryAnthemTrackId: { _eq: 3421 } }
]
}
}
) {
id
songs {
primaryAnthemTrackId
secondaryAnthemTrackId
}
}
}

View File

@ -81,6 +81,82 @@ V1(
},
},
),
Alias(
Identifier(
"noargs",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"ActorsByMovie",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"actor_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"actor_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"movie_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"movie_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -81,6 +81,82 @@ V1(
},
},
),
Alias(
Identifier(
"noargs",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"ActorsByMovie",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"actor_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"actor_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"movie_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"movie_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -81,6 +81,82 @@ V1(
},
},
),
Alias(
Identifier(
"noargs",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"ActorsByMovie",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"actor_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"actor_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"movie_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"movie_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -7,7 +7,75 @@ V1(
queries: {
Alias(
Identifier(
"getActorsByName",
"leonardoDiCaprio",
),
): Command(
CommandSelection {
target: CommandTarget {
subgraph: SubgraphName(
"default",
),
command_name: CommandName(
Identifier(
"get_actors_by_name",
),
),
arguments: {
ArgumentName(
Identifier(
"name_filter",
),
): Literal(
Object {
"first_name": String("Leonardo"),
"surname": String("DiCaprio"),
},
),
},
},
selection: Some(
{
Alias(
Identifier(
"movie_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"movie_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"name",
),
),
arguments: {},
},
selection: None,
},
),
},
),
},
),
Alias(
Identifier(
"kate",
),
): Command(
CommandSelection {

View File

@ -7,7 +7,129 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithLimitZero",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
0,
),
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimitOne",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimitTwo",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,259 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithLimit0Offset0",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
0,
),
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit1Offset0",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit1Offset1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit2Offset1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
2,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit2Offset2",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,259 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithLimit0Offset0",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
0,
),
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit1Offset0",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit1Offset1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit2Offset1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
2,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit2Offset2",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,259 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithLimit0Offset0",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
0,
),
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit1Offset0",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit1Offset1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit2Offset1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
2,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimit2Offset2",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,129 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithLimitZero",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
0,
),
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimitOne",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimitTwo",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,129 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithLimitZero",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
0,
),
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimitOne",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithLimitTwo",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,129 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithOffsetZero",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithOffsetOne",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithOffsetTwo",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,129 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithOffsetZero",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithOffsetOne",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithOffsetTwo",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,129 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyWithOffsetZero",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: Some(
0,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithOffsetOne",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithOffsetTwo",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,66 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNegativeLimit",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithNegativeOffset",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,66 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNegativeLimit",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithNegativeOffset",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,66 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNegativeLimit",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyWithNegativeOffset",
),
): Model(
ModelSelection {

View File

@ -9,6 +9,77 @@ V1(
Identifier(
"AuthorMany",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"order_by",
),
): Literal(
Array [
Object {
"first_name": String("Asc"),
},
],
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"a1",
),
): Model(
ModelSelection {
target: ModelTarget {

View File

@ -7,7 +7,82 @@ V1(
queries: {
Alias(
Identifier(
"InstitutionMany",
"asc",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"institutions",
),
),
arguments: {
ArgumentName(
Identifier(
"order_by",
),
): Literal(
Array [
Object {
"location": Array [
Object {
"city": String("Asc"),
},
],
},
],
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"location",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"location",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"desc",
),
): Model(
ModelSelection {

View File

@ -21,20 +21,6 @@ V1(
),
),
arguments: {
ArgumentName(
Identifier(
"limit_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"offset_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"order_by_custom",
@ -42,7 +28,7 @@ V1(
): Literal(
Array [
Object {
"first_name": String("Desc_custom"),
"first_name": String("Asc_custom"),
},
],
),
@ -153,6 +139,91 @@ V1(
},
},
),
Alias(
Identifier(
"a1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"limit_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"offset_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"order_by_custom",
),
): Literal(
Array [
Object {
"first_name": String("Desc_custom"),
},
],
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -21,20 +21,6 @@ V1(
),
),
arguments: {
ArgumentName(
Identifier(
"limit_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"offset_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"order_by_custom",
@ -42,7 +28,7 @@ V1(
): Literal(
Array [
Object {
"first_name": String("Desc_custom"),
"first_name": String("Asc_custom"),
},
],
),
@ -153,6 +139,91 @@ V1(
},
},
),
Alias(
Identifier(
"a1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"limit_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"offset_custom",
),
): Literal(
Number(1),
),
ArgumentName(
Identifier(
"order_by_custom",
),
): Literal(
Array [
Object {
"first_name": String("Desc_custom"),
},
],
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -28,19 +28,15 @@ V1(
): Literal(
Array [
Object {
"first_name": String("Desc"),
"first_name": String("Asc"),
},
],
),
},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
1,
),
limit: None,
offset: None,
},
selection: {
Alias(
@ -141,6 +137,81 @@ V1(
},
},
),
Alias(
Identifier(
"a1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"order_by",
),
): Literal(
Array [
Object {
"first_name": String("Desc"),
},
],
),
},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -28,19 +28,15 @@ V1(
): Literal(
Array [
Object {
"first_name": String("Desc"),
"first_name": String("Asc"),
},
],
),
},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
1,
),
limit: None,
offset: None,
},
selection: {
Alias(
@ -141,6 +137,81 @@ V1(
},
},
),
Alias(
Identifier(
"a1",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"order_by",
),
): Literal(
Array [
Object {
"first_name": String("Desc"),
},
],
),
},
filter: None,
order_by: [],
limit: Some(
1,
),
offset: Some(
1,
),
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -7,7 +7,7 @@ V1(
queries: {
Alias(
Identifier(
"ArticlesByAuthorMany",
"article_author_match",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,76 @@ V1(
queries: {
Alias(
Identifier(
"ArticlesByAuthorMany",
"article_author_match",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"ArticlesByAuthor",
),
),
arguments: {
ArgumentName(
Identifier(
"args_custom",
),
): Literal(
Object {
"author_id": Number(2),
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"article_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"article_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"title",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"title",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"article_author_mismatch",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,76 @@ V1(
queries: {
Alias(
Identifier(
"ArticlesByAuthorMany",
"article_author_match",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"ArticlesByAuthor",
),
),
arguments: {
ArgumentName(
Identifier(
"args_custom",
),
): Literal(
Object {
"author_id": Number(2),
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"article_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"article_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"title",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"title",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"article_author_mismatch",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,74 @@ V1(
queries: {
Alias(
Identifier(
"ArticlesByAuthorMany",
"article_author_match",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"ArticlesByAuthor",
),
),
arguments: {
ArgumentName(
Identifier(
"author_id",
),
): Literal(
Number(2),
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"article_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"article_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"title",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"title",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"article_author_mismatch",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,230 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyNestedBool",
),
): Model(
ModelSelection {
@ -105,7 +328,230 @@ V1(
),
Alias(
Identifier(
"AuthorTwoMany",
"AuthorTwoManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyNestedBool",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,230 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyNestedBool",
),
): Model(
ModelSelection {
@ -105,7 +328,230 @@ V1(
),
Alias(
Identifier(
"AuthorTwoMany",
"AuthorTwoManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyNestedBool",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,273 @@ V1(
queries: {
Alias(
Identifier(
"Track",
"TrackNameEq",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_eq": Number(1),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGtAndLt",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_gt": Number(1),
"_lt": Number(3),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGteAndLte",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_gte": Number(1),
"_lte": Number(3),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGteAndLteAndNeq",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,273 @@ V1(
queries: {
Alias(
Identifier(
"Track",
"TrackNameEq",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_eq": Number(1),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGtAndLt",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_gt": Number(1),
"_lt": Number(3),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGteAndLte",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_gte": Number(1),
"_lte": Number(3),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGteAndLteAndNeq",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,273 @@ V1(
queries: {
Alias(
Identifier(
"Track",
"TrackNameEq",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_eq": Number(1),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGtAndLt",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_gt": Number(1),
"_lt": Number(3),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGteAndLte",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Tracks",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"TrackId": Object {
"_gte": Number(1),
"_lte": Number(3),
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"AlbumId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"AlbumId",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"Name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"Name",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"TrackId",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"TrackId",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"TrackGteAndLteAndNeq",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,80 @@ V1(
queries: {
Alias(
Identifier(
"InstitutionMany",
"where_does_john_hughes_work",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"institutions",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"staff": Object {
"last_name": Object {
"_eq": String("Hughes"),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"location",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"location",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"where_has_staff_with_a_dog",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,148 @@ V1(
queries: {
Alias(
Identifier(
"InstitutionMany",
"match_london",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"institutions",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"location": Object {
"city": Object {
"_eq": String("London"),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"location",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"location",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"location_country",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"location",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"staff",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"staff",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"staff_first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"staff",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"departments",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"departments",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"match_uk",
),
): Model(
ModelSelection {
@ -148,6 +289,164 @@ V1(
},
},
),
Alias(
Identifier(
"match_two_nested_fields",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"institutions",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"songs": Object {
"primaryAnthemTrackId": Object {
"_eq": Number(2270),
},
"secondaryAnthemTrackId": Object {
"_eq": Number(2271),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"songs",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"songs",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"nested_logical_operators",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"institutions",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"songs": Object {
"_or": Array [
Object {
"primaryAnthemTrackId": Object {
"_eq": Number(2270),
},
},
Object {
"primaryAnthemTrackId": Object {
"_eq": Number(3421),
},
},
],
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"songs",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"songs",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
},
},
)

View File

@ -7,7 +7,230 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyNestedBool",
),
): Model(
ModelSelection {
@ -105,7 +328,230 @@ V1(
),
Alias(
Identifier(
"AuthorTwoMany",
"AuthorTwoManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyNestedBool",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,230 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyNestedBool",
),
): Model(
ModelSelection {
@ -105,7 +328,230 @@ V1(
),
Alias(
Identifier(
"AuthorTwoMany",
"AuthorTwoManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"AuthorsTwo",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorTwoManyNestedBool",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,230 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyNestedBool",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,230 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_not": Object {
"first_name": Object {
"_is_null": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_or": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where",
),
): Literal(
Object {
"_and": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyNestedBool",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,155 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where_custom",
),
): Literal(
Object {
"_not_custom": Object {
"first_name": Object {
"_is_null_custom": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where_custom",
),
): Literal(
Object {
"_or_custom": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {

View File

@ -7,7 +7,155 @@ V1(
queries: {
Alias(
Identifier(
"AuthorMany",
"AuthorManyNot",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where_custom",
),
): Literal(
Object {
"_not_custom": Object {
"first_name": Object {
"_is_null_custom": Bool(true),
},
},
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyOr",
),
): Model(
ModelSelection {
target: ModelTarget {
subgraph: SubgraphName(
"default",
),
model_name: ModelName(
Identifier(
"Authors",
),
),
arguments: {
ArgumentName(
Identifier(
"where_custom",
),
): Literal(
Object {
"_or_custom": Array [
Object {
"first_name": Object {
"_like": String("Pet%"),
},
},
],
},
),
},
filter: None,
order_by: [],
limit: None,
offset: None,
},
selection: {
Alias(
Identifier(
"author_id",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"author_id",
),
),
arguments: {},
},
selection: None,
},
),
Alias(
Identifier(
"first_name",
),
): Field(
ObjectFieldSelection {
target: ObjectFieldTarget {
field_name: FieldName(
Identifier(
"first_name",
),
),
arguments: {},
},
selection: None,
},
),
},
},
),
Alias(
Identifier(
"AuthorManyAnd",
),
): Model(
ModelSelection {

View File

@ -5,7 +5,16 @@ expression: rowsets
{
"Ok": [
{
"rows": []
"rows": [
{
"author_id": 1,
"first_name": "Peter"
},
{
"author_id": 2,
"first_name": "John"
}
]
}
]
}

View File

@ -5,7 +5,12 @@ expression: rowsets
{
"Ok": [
{
"rows": []
"rows": [
{
"author_id": 1,
"first_name": "Peter"
}
]
}
]
}

View File

@ -5,7 +5,12 @@ expression: rowsets
{
"Ok": [
{
"rows": []
"rows": [
{
"author_id": 2,
"first_name": "John"
}
]
}
]
}

View File

@ -135,9 +135,9 @@ fn analyze_input_annotation(annotation: &graphql_schema::InputAnnotation) -> Vec
}));
}
graphql_schema::InputAnnotation::BooleanExpression(
graphql_schema::BooleanExpressionAnnotation::BooleanExpressionArgument { field },
graphql_schema::BooleanExpressionAnnotation::ObjectBooleanExpressionField(field),
) => match field {
graphql_schema::ModelFilterArgument::Field {
graphql_schema::ObjectBooleanExpressionField::Field {
field_name,
object_type,
deprecated,
@ -154,7 +154,9 @@ fn analyze_input_annotation(annotation: &graphql_schema::InputAnnotation) -> Vec
deprecated_reason: reason,
}));
}
graphql_schema::ModelFilterArgument::RelationshipField(relationship_annotation) => {
graphql_schema::ObjectBooleanExpressionField::RelationshipField(
relationship_annotation,
) => {
let DeprecatedDetails {
is_deprecated,
reason,
@ -172,12 +174,13 @@ fn analyze_input_annotation(annotation: &graphql_schema::InputAnnotation) -> Vec
deprecated_reason: reason,
}));
}
graphql_schema::ModelFilterArgument::AndOp
| graphql_schema::ModelFilterArgument::OrOp
| graphql_schema::ModelFilterArgument::NotOp => {}
graphql_schema::ObjectBooleanExpressionField::AndOp
| graphql_schema::ObjectBooleanExpressionField::OrOp
| graphql_schema::ObjectBooleanExpressionField::NotOp => {}
},
graphql_schema::InputAnnotation::BooleanExpression(
graphql_schema::BooleanExpressionAnnotation::BooleanExpression,
graphql_schema::BooleanExpressionAnnotation::BooleanExpressionRootField
| graphql_schema::BooleanExpressionAnnotation::ScalarBooleanExpressionField(_),
)
| graphql_schema::InputAnnotation::CommandArgument { .. }
| graphql_schema::InputAnnotation::Relay(_)
@ -231,8 +234,6 @@ fn analyze_model_input_annotation(
}
graphql_schema::ModelInputAnnotation::ModelArgumentsExpression
| graphql_schema::ModelInputAnnotation::ModelArgument { .. }
| graphql_schema::ModelInputAnnotation::ComparisonOperation { .. }
| graphql_schema::ModelInputAnnotation::IsNullOperation
| graphql_schema::ModelInputAnnotation::ModelOrderByExpression
| graphql_schema::ModelInputAnnotation::ModelOrderByNestedExpression { .. }
| graphql_schema::ModelInputAnnotation::ModelOrderByDirection { .. }

View File

@ -16,7 +16,7 @@ pub fn to_opendd_ir(operation: &Operation<GDS>) -> QueryRequest {
}
let mut queries = IndexMap::new();
for query in operation.selection_set.fields.values() {
for (query_alias, query) in &operation.selection_set.fields {
for field_call in query.field_calls.values() {
match field_call.info.generic {
graphql_schema::Annotation::Output(
@ -29,8 +29,7 @@ pub fn to_opendd_ir(operation: &Operation<GDS>) -> QueryRequest {
},
),
) => {
let opendd_alias =
Alias::new(Identifier::new(field_call.name.as_str()).unwrap());
let opendd_alias = Alias::new(Identifier::new(query_alias.0.as_str()).unwrap());
let selection = to_model_selection(&query.selection_set.fields);
@ -60,8 +59,7 @@ pub fn to_opendd_ir(operation: &Operation<GDS>) -> QueryRequest {
graphql_schema::RootFieldAnnotation::FunctionCommand { name, .. },
),
) => {
let opendd_alias =
Alias::new(Identifier::new(field_call.name.as_str()).unwrap());
let opendd_alias = Alias::new(Identifier::new(query_alias.0.as_str()).unwrap());
let selection = to_model_selection(&query.selection_set.fields);
@ -102,8 +100,8 @@ fn to_model_arguments(
let mut model_limit = None;
for (name, argument) in arguments {
// currently we are magically matching on strings, really we should be looking up the correct names
// for each thing in `graphql_config` in resolved metadata
// currently we are magically matching on strings, really we should be using the graphql field annotations
// to determine the role of each field
match name.as_str() {
"offset" => {
if let Some(offset_value) = match &argument.value {

View File

@ -5,15 +5,17 @@ use metadata_resolve::{DataConnectorLink, FieldMapping, Qualified};
use open_dds::models::ModelName;
use open_dds::relationships::{RelationshipName, RelationshipType};
use serde::Serialize;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::ops::Deref;
use crate::error;
use crate::model_tracking::count_model;
use graphql_schema::FilterRelationshipAnnotation;
use graphql_schema::GDS;
use graphql_schema::{self};
use graphql_schema::{BooleanExpressionAnnotation, InputAnnotation, ObjectFieldKind};
use graphql_schema::{
BooleanExpressionAnnotation, InputAnnotation, ModelInputAnnotation, ObjectFieldKind,
FilterRelationshipAnnotation, ObjectBooleanExpressionField, ScalarBooleanExpressionField,
};
use open_dds::{
data_connector::{DataConnectorColumnName, DataConnectorOperatorName},
@ -52,125 +54,137 @@ pub fn resolve_filter_expression<'s>(
type_mappings: &'s BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
usage_counts: &mut UsagesCounts,
) -> Result<Expression<'s>, error::Error> {
let mut expressions = Vec::new();
for field in fields.values() {
let field_filter_expression =
build_filter_expression(field, data_connector_link, type_mappings, usage_counts)?;
expressions.push(field_filter_expression);
}
Ok(Expression::mk_and(expressions))
}
fn build_filter_expression<'s>(
field: &normalized_ast::InputField<'s, GDS>,
data_connector_link: &'s DataConnectorLink,
type_mappings: &'s BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
usage_counts: &mut UsagesCounts,
) -> Result<Expression<'s>, error::Error> {
let boolean_expression_annotation = get_boolean_expression_annotation(field.info.generic)?;
build_filter_expression_from_boolean_expression(
boolean_expression_annotation,
field,
resolve_object_boolean_expression(
fields,
data_connector_link,
type_mappings,
&mut vec![],
&[],
usage_counts,
)
}
fn build_filter_expression_from_boolean_expression<'s>(
boolean_expression_annotation: &'s BooleanExpressionAnnotation,
field: &normalized_ast::InputField<'s, GDS>,
fn resolve_object_boolean_expression<'s>(
fields: &IndexMap<ast::Name, normalized_ast::InputField<'s, GDS>>,
data_connector_link: &'s DataConnectorLink,
type_mappings: &'s BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
field_path: &mut Vec<DataConnectorColumnName>,
column_path: &[&'s DataConnectorColumnName],
usage_counts: &mut UsagesCounts,
) -> Result<Expression<'s>, error::Error> {
match boolean_expression_annotation {
// "_and"
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: graphql_schema::ModelFilterArgument::AndOp,
} => {
// The "_and" field value should be a list
let and_values = field.value.as_list()?;
let field_expressions = fields
.values()
.map(|field| {
let field_annotation =
extract_object_boolean_expression_field_annotation(field.info.generic)?;
let and_expressions = and_values
.iter()
.map(|value| {
let value_object = value.as_object()?;
resolve_filter_object(
value_object,
let field_expression = match field_annotation {
// "_and" field
ObjectBooleanExpressionField::AndOp => {
// The "_and" field value should be a list
let and_values = field.value.as_list()?;
let and_expressions = and_values
.iter()
.map(|value| {
let value_object = value.as_object()?;
resolve_object_boolean_expression(
value_object,
data_connector_link,
type_mappings,
column_path,
usage_counts,
)
})
.collect::<Result<Vec<_>, _>>()?;
Expression::mk_and(and_expressions)
}
// "_or" field
ObjectBooleanExpressionField::OrOp => {
// The "_or" field value should be a list
let or_values = field.value.as_list()?;
let or_expressions = or_values
.iter()
.map(|value| {
let value_object = value.as_object()?;
resolve_object_boolean_expression(
value_object,
data_connector_link,
type_mappings,
column_path,
usage_counts,
)
})
.collect::<Result<Vec<_>, _>>()?;
Expression::mk_or(or_expressions)
}
// "_not" field
ObjectBooleanExpressionField::NotOp => {
// The "_not" field value should be an object
let not_value = field.value.as_object()?;
let not_filter_expression = resolve_object_boolean_expression(
not_value,
data_connector_link,
type_mappings,
column_path,
usage_counts,
)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Expression::mk_and(and_expressions))
}
// "_or"
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: graphql_schema::ModelFilterArgument::OrOp,
} => {
// The "_or" field value should be a list
let or_values = field.value.as_list()?;
let or_expressions = or_values
.iter()
.map(|value| {
let value_object = value.as_object()?;
resolve_filter_object(
value_object,
data_connector_link,
type_mappings,
usage_counts,
)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Expression::mk_or(or_expressions))
}
// "_not"
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: graphql_schema::ModelFilterArgument::NotOp,
} => {
// The "_not" field value should be an object
let not_value = field.value.as_object()?;
let not_filter_expression =
resolve_filter_object(not_value, data_connector_link, type_mappings, usage_counts)?;
Ok(Expression::mk_not(not_filter_expression))
}
// The column that we want to use for filtering.
BooleanExpressionAnnotation::BooleanExpressionArgument {
field:
graphql_schema::ModelFilterArgument::Field {
)?;
Expression::mk_not(not_filter_expression)
}
// comparableField field
ObjectBooleanExpressionField::Field {
field_name,
object_type,
object_field_kind,
..
},
} => {
let FieldMapping { column, .. } =
get_field_mapping_of_field_name(type_mappings, object_type, field_name)?;
deprecated: _,
} => {
let FieldMapping { column, .. } =
get_field_mapping_of_field_name(type_mappings, object_type, field_name)?;
let inner_is_array_field = matches!(object_field_kind, ObjectFieldKind::Array);
let field_value = field.value.as_object()?;
build_comparison_expression(
field,
field_path,
inner_is_array_field,
&column,
data_connector_link,
type_mappings,
)
}
// Relationship field used for filtering.
// This relationship can either point to another relationship or a column.
BooleanExpressionAnnotation::BooleanExpressionArgument {
field:
graphql_schema::ModelFilterArgument::RelationshipField(FilterRelationshipAnnotation {
match object_field_kind {
ObjectFieldKind::Object => {
// Append the current column to the column_path before descending into the nested object expression
let field_path = column_path
.iter()
.copied()
.chain([column])
.collect::<Vec<_>>();
resolve_object_boolean_expression(
field_value,
data_connector_link,
type_mappings,
&field_path,
usage_counts,
)?
}
ObjectFieldKind::ObjectArray => {
let inner_expression = resolve_object_boolean_expression(
field_value,
data_connector_link,
type_mappings,
&[], // Reset the column path because we're nesting the expression inside an exists that itself captures the field path
usage_counts,
)?;
Expression::LocalNestedArray {
column: column.clone(),
field_path: column_path.iter().copied().cloned().collect(),
predicate: Box::new(inner_expression),
}
}
ObjectFieldKind::Scalar => resolve_scalar_boolean_expression(
field_value,
data_connector_link,
column_path,
column,
)?,
}
}
ObjectBooleanExpressionField::RelationshipField(FilterRelationshipAnnotation {
relationship_name,
relationship_type,
source_type,
@ -179,49 +193,115 @@ fn build_filter_expression_from_boolean_expression<'s>(
target_model_name,
mappings,
deprecated: _,
}),
} => {
// Add the target model being used in the usage counts
count_model(target_model_name, usage_counts);
}) => {
// Add the target model being used in the usage counts
count_model(target_model_name, usage_counts);
// This map contains the relationships or the columns of the
// relationship that needs to be used for ordering.
let filter_object = field.value.as_object()?;
// This map contains the relationships or the columns of the
// relationship that needs to be used for ordering.
let filter_object = field.value.as_object()?;
let mut expressions = Vec::new();
let relationship_predicate = resolve_object_boolean_expression(
filter_object,
&target_source.model.data_connector,
&target_source.model.type_mappings,
&[], // We're traversing across the relationship, so we reset the field path
usage_counts,
)?;
for field in filter_object.values() {
let field_filter_expression = build_filter_expression(
field,
&target_source.model.data_connector,
&target_source.model.type_mappings,
usage_counts,
)?;
expressions.push(field_filter_expression);
}
// build and return relationshp comparison expression
build_relationship_comparison_expression(
type_mappings,
column_path,
data_connector_link,
relationship_name,
relationship_type,
source_type,
target_model_name,
target_source,
target_type,
mappings,
relationship_predicate,
)?
}
};
let relationship_predicate = Expression::mk_and(expressions);
Ok(field_expression)
})
.collect::<Result<Vec<Expression>, error::Error>>()?;
// build and return relationshp comparison expression
build_relationship_comparison_expression(
type_mappings,
field_path,
data_connector_link,
relationship_name,
relationship_type,
source_type,
target_model_name,
target_source,
target_type,
mappings,
relationship_predicate,
)
Ok(Expression::mk_and(field_expressions))
}
fn extract_object_boolean_expression_field_annotation(
annotation: &graphql_schema::Annotation,
) -> Result<&ObjectBooleanExpressionField, error::Error> {
match annotation {
graphql_schema::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::ObjectBooleanExpressionField(
object_boolean_expression_field,
),
)) => Ok(object_boolean_expression_field),
_ => Err(error::InternalEngineError::UnexpectedAnnotation {
annotation: annotation.clone(),
}
other_boolean_annotation => Err(error::InternalEngineError::UnexpectedAnnotation {
annotation: graphql_schema::Annotation::Input(InputAnnotation::BooleanExpression(
other_boolean_annotation.clone(),
)),
})?,
.into()),
}
}
fn resolve_scalar_boolean_expression<'s>(
fields: &IndexMap<ast::Name, normalized_ast::InputField<'s, GDS>>,
data_connector_link: &'s DataConnectorLink,
column_path: &[&'s DataConnectorColumnName],
column: &DataConnectorColumnName,
) -> Result<Expression<'s>, error::Error> {
let field_expressions = fields
.values()
.map(|field| {
let field_annotation =
extract_scalar_boolean_expression_field_annotation(field.info.generic)?;
let field_expression = match field_annotation {
ScalarBooleanExpressionField::IsNullOperation => {
build_is_null_expression(column_path, column, &field.value)?
}
ScalarBooleanExpressionField::ComparisonOperation { operator_mapping } => {
let operator =
operator_mapping
.get(&data_connector_link.name)
.ok_or_else(|| {
error::InternalEngineError::OperatorMappingError(
error::OperatorMappingError::MissingEntryForDataConnector {
column_name: column.clone(),
data_connector_name: data_connector_link.name.clone(),
},
)
})?;
build_binary_comparison_expression(operator, column_path, column, &field.value)
}
};
Ok(field_expression)
})
.collect::<Result<Vec<Expression>, error::Error>>()?;
Ok(Expression::mk_and(field_expressions))
}
fn extract_scalar_boolean_expression_field_annotation(
annotation: &graphql_schema::Annotation,
) -> Result<&ScalarBooleanExpressionField, error::Error> {
match annotation {
graphql_schema::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::ScalarBooleanExpressionField(
scalar_boolean_expression_field,
),
)) => Ok(scalar_boolean_expression_field),
_ => Err(error::InternalEngineError::UnexpectedAnnotation {
annotation: annotation.clone(),
}
.into()),
}
}
@ -265,7 +345,7 @@ fn get_relationship_predicate_execution_strategy(
/// and passed as `relationship_predicate`.
pub(crate) fn build_relationship_comparison_expression<'s>(
type_mappings: &'s BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
field_path: &[DataConnectorColumnName],
column_path: &[&'s DataConnectorColumnName],
data_connector_link: &'s DataConnectorLink,
relationship_name: &'s RelationshipName,
relationship_type: &'s RelationshipType,
@ -276,7 +356,16 @@ pub(crate) fn build_relationship_comparison_expression<'s>(
mappings: &'s Vec<metadata_resolve::RelationshipModelMapping>,
relationship_predicate: Expression<'s>,
) -> Result<Expression<'s>, error::Error> {
// Determinde whether the relationship is local or remote
if !column_path.is_empty() {
return Err(
error::InternalDeveloperError::NestedObjectRelationshipInPredicate {
relationship_name: relationship_name.clone(),
}
.into(),
);
}
// Determine whether the relationship is local or remote
match get_relationship_predicate_execution_strategy(
data_connector_link,
&target_source.model.data_connector,
@ -317,7 +406,8 @@ pub(crate) fn build_relationship_comparison_expression<'s>(
} = get_field_mapping_of_field_name(type_mappings, source_type, source_field)?;
let equal_operators = comparison_operators
.map(|ops| ops.equality_operators)
.as_ref()
.map(|ops| Cow::Borrowed(&ops.equality_operators))
.unwrap_or_default();
let eq_operator = equal_operators.first().ok_or_else(|| {
@ -331,8 +421,8 @@ pub(crate) fn build_relationship_comparison_expression<'s>(
})?;
let source_ndc_column = SourceNdcColumn {
column: source_column,
field_path: field_path.to_owned(),
column: source_column.clone(),
field_path: column_path.iter().copied().cloned().collect(),
eq_operator: eq_operator.clone(),
};
@ -361,144 +451,26 @@ pub(crate) fn build_relationship_comparison_expression<'s>(
}
}
fn build_comparison_expression<'s>(
field: &normalized_ast::InputField<'s, GDS>,
field_path: &mut Vec<DataConnectorColumnName>,
is_array_field: bool,
column: &DataConnectorColumnName,
data_connector_link: &'s DataConnectorLink,
type_mappings: &'s BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
) -> Result<Expression<'s>, error::Error> {
let mut expressions = Vec::new();
for (_op_name, op_value) in field.value.as_object()? {
match op_value.info.generic {
graphql_schema::Annotation::Input(InputAnnotation::Model(
ModelInputAnnotation::IsNullOperation,
)) => {
let expression =
build_is_null_expression(column, &op_value.value, field_path.clone())?;
expressions.push(expression);
}
graphql_schema::Annotation::Input(InputAnnotation::Model(
ModelInputAnnotation::ComparisonOperation { operator_mapping },
)) => {
let operator =
operator_mapping
.get(&data_connector_link.name)
.ok_or_else(|| {
error::InternalEngineError::OperatorMappingError(
error::OperatorMappingError::MissingEntryForDataConnector {
column_name: column.clone(),
data_connector_name: data_connector_link.name.clone(),
},
)
})?;
let expression = build_binary_comparison_expression(
operator,
column,
&op_value.value,
field_path,
);
expressions.push(expression);
}
// Nested field comparison
graphql_schema::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field:
graphql_schema::ModelFilterArgument::Field {
field_name: inner_field_name,
object_field_kind,
object_type: inner_object_type,
..
},
},
)) => {
// get correct inner column name
let FieldMapping {
column: inner_column,
..
} = get_field_mapping_of_field_name(
type_mappings,
inner_object_type,
inner_field_name,
)?;
let inner_is_array_field = matches!(object_field_kind, ObjectFieldKind::Array);
if is_array_field {
// if we're matching in an array field, we look for the inner column directly
let inner_expression = build_comparison_expression(
op_value,
field_path,
inner_is_array_field,
&inner_column,
data_connector_link,
type_mappings,
)?;
// and then wrap it in an `exists`
let exists_wrapper = Expression::LocalNestedArray {
column: column.clone(),
field_path: field_path.clone(),
predicate: Box::new(inner_expression),
};
expressions.push(exists_wrapper);
} else {
// otherwise we add to the field path
field_path.push(inner_column.clone());
// and look for the main column inside
let inner_expression = build_comparison_expression(
op_value,
field_path,
inner_is_array_field,
column,
data_connector_link,
type_mappings,
)?;
expressions.push(inner_expression);
}
}
// Nested relationship comparison
graphql_schema::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field:
graphql_schema::ModelFilterArgument::RelationshipField(
FilterRelationshipAnnotation {
relationship_name, ..
},
),
},
)) => Err(
error::InternalDeveloperError::NestedObjectRelationshipInPredicate {
relationship_name: relationship_name.clone(),
},
)?,
annotation => Err(error::InternalEngineError::UnexpectedAnnotation {
annotation: annotation.clone(),
})?,
}
}
Ok(Expression::mk_and(expressions))
}
/// Resolve `_is_null` GraphQL boolean operator
fn build_is_null_expression<'s>(
column_path: &[&DataConnectorColumnName],
column: &DataConnectorColumnName,
value: &normalized_ast::Value<'s, GDS>,
field_path: Vec<DataConnectorColumnName>,
) -> Result<Expression<'s>, error::Error> {
// Build an 'IsNull' unary comparison expression
let unary_comparison_expression =
Expression::LocalField(LocalFieldComparison::UnaryComparison {
column: ComparisonTarget::Column {
name: column.clone(),
field_path,
// The column name is the root column
name: column_path.first().map_or(column, Deref::deref).clone(),
// The field path is the nesting path inside the root column, if any
field_path: column_path
.iter()
.copied()
.chain([column])
.skip(1)
.cloned()
.collect(),
},
operator: metadata_resolve::UnaryComparisonOperator::IsNull,
});
@ -516,14 +488,22 @@ fn build_is_null_expression<'s>(
/// Generate a binary comparison operator
fn build_binary_comparison_expression<'s>(
operator: &DataConnectorOperatorName,
column_path: &[&DataConnectorColumnName],
column: &DataConnectorColumnName,
value: &normalized_ast::Value<'s, GDS>,
field_path: &[DataConnectorColumnName],
) -> Expression<'s> {
Expression::LocalField(LocalFieldComparison::BinaryComparison {
column: ComparisonTarget::Column {
name: column.clone(),
field_path: field_path.to_vec(),
// The column name is the root column
name: column_path.first().map_or(column, Deref::deref).clone(),
// The field path is the nesting path inside the root column, if any
field_path: column_path
.iter()
.copied()
.chain([column])
.skip(1)
.cloned()
.collect(),
},
operator: operator.clone(),
value: ComparisonValue::Scalar {
@ -532,45 +512,12 @@ fn build_binary_comparison_expression<'s>(
})
}
fn resolve_filter_object<'s>(
fields: &IndexMap<ast::Name, normalized_ast::InputField<'s, GDS>>,
data_connector_link: &'s DataConnectorLink,
type_mappings: &'s BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
usage_counts: &mut UsagesCounts,
) -> Result<Expression<'s>, error::Error> {
let mut expressions = Vec::new();
for field in fields.values() {
expressions.push(build_filter_expression(
field,
data_connector_link,
type_mappings,
usage_counts,
)?);
}
Ok(Expression::mk_and(expressions))
}
fn get_boolean_expression_annotation(
annotation: &graphql_schema::Annotation,
) -> Result<&BooleanExpressionAnnotation, error::Error> {
match annotation {
graphql_schema::Annotation::Input(InputAnnotation::BooleanExpression(
boolean_expression_annotation,
)) => Ok(boolean_expression_annotation),
_ => Err(error::InternalEngineError::UnexpectedAnnotation {
annotation: annotation.clone(),
}
.into()),
}
}
/// get column name for field name
fn get_field_mapping_of_field_name(
type_mappings: &BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
fn get_field_mapping_of_field_name<'a>(
type_mappings: &'a BTreeMap<Qualified<CustomTypeName>, metadata_resolve::TypeMapping>,
type_name: &Qualified<CustomTypeName>,
field_name: &FieldName,
) -> Result<metadata_resolve::FieldMapping, error::Error> {
) -> Result<&'a metadata_resolve::FieldMapping, error::Error> {
let type_mapping = type_mappings.get(type_name).ok_or_else(|| {
error::InternalDeveloperError::TypeMappingNotFound {
type_name: type_name.clone(),
@ -582,7 +529,6 @@ fn get_field_mapping_of_field_name(
.ok_or_else(|| error::InternalDeveloperError::FieldMappingNotFound {
type_name: type_name.clone(),
field_name: field_name.clone(),
})?
.clone()),
})?),
}
}

View File

@ -339,7 +339,7 @@ fn read_filter_input_arguments<'s>(
// Where argument
Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpression,
BooleanExpressionAnnotation::BooleanExpressionRootField,
)) => {
if filter_clause.is_some() {
return Err(error::InternalEngineError::UnexpectedAnnotation {

View File

@ -110,7 +110,7 @@ pub fn select_many_generate_ir<'n, 's>(
},
Annotation::Input(graphql_schema::InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpression,
BooleanExpressionAnnotation::BooleanExpressionRootField,
)) => {
where_clause = Some(filter::resolve_filter_expression(
argument.value.as_object()?,

View File

@ -107,7 +107,7 @@ pub fn generate_model_relationship_ir<'s>(
}
}
InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpression,
BooleanExpressionAnnotation::BooleanExpressionRootField,
) => {
if let Some(model_source) = &relationship_annotation.target_source {
where_clause = Some(filter::resolve_filter_expression(

View File

@ -1,6 +1,7 @@
use hasura_authn_core::Role;
use lang_graphql::ast::common as ast;
use lang_graphql::schema::{self as gql_schema};
use open_dds::data_connector::DataConnectorName;
use open_dds::types::Deprecated;
use open_dds::{
relationships::RelationshipType,
@ -9,6 +10,7 @@ use open_dds::{
use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
use super::types::input_type;
use super::types::output_type::get_object_type_representation;
use super::types::output_type::relationship::FilterRelationshipAnnotation;
use super::types::{BooleanExpressionAnnotation, InputAnnotation, ObjectFieldKind, TypeId};
@ -16,9 +18,10 @@ use metadata_resolve::{
mk_name, BooleanExpressionComparableRelationship, ComparisonExpressionInfo,
GlobalGraphqlConfig, IncludeLogicalOperators, ModelExpressionType, ModelWithArgumentPresets,
ObjectBooleanExpressionGraphqlConfig, ObjectBooleanExpressionType,
ObjectComparisonExpressionInfo, ObjectComparisonKind, ObjectTypeWithRelationships, Qualified,
RelationshipCapabilities, RelationshipField, RelationshipModelMapping,
ResolvedObjectBooleanExpressionType, ScalarBooleanExpressionGraphqlConfig,
ObjectComparisonExpressionInfo, ObjectComparisonKind, ObjectTypeWithRelationships,
OperatorMapping, Qualified, QualifiedTypeReference, RelationshipCapabilities,
RelationshipField, RelationshipModelMapping, ResolvedObjectBooleanExpressionType,
ScalarBooleanExpressionGraphqlConfig,
};
use crate::mk_deprecation_status;
@ -86,9 +89,9 @@ fn build_builtin_operator_schema(
not_field_name.clone(),
None,
types::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: types::ModelFilterArgument::NotOp,
},
BooleanExpressionAnnotation::ObjectBooleanExpressionField(
types::ObjectBooleanExpressionField::NotOp,
),
)),
ast::TypeContainer::named_null(gql_schema::RegisteredTypeName::new(
type_name.0.clone(),
@ -106,9 +109,9 @@ fn build_builtin_operator_schema(
and_field_name.clone(),
None,
types::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: types::ModelFilterArgument::AndOp,
},
BooleanExpressionAnnotation::ObjectBooleanExpressionField(
types::ObjectBooleanExpressionField::AndOp,
),
)),
ast::TypeContainer::list_null(ast::TypeContainer::named_non_null(
gql_schema::RegisteredTypeName::new(type_name.0.clone()),
@ -125,9 +128,9 @@ fn build_builtin_operator_schema(
or_field_name.clone(),
None,
types::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: types::ModelFilterArgument::OrOp,
},
BooleanExpressionAnnotation::ObjectBooleanExpressionField(
types::ObjectBooleanExpressionField::OrOp,
),
)),
ast::TypeContainer::list_null(ast::TypeContainer::named_non_null(
gql_schema::RegisteredTypeName::new(type_name.0.clone()),
@ -160,7 +163,7 @@ fn build_comparable_fields_schema(
.map_err(metadata_resolve::WithContext::from)?;
if let Some(scalar_boolean_expression_graphql) = scalar_fields_graphql.get(field_name) {
let registered_type_name = get_scalar_comparison_input_type(
let registered_type_name = get_scalar_boolean_expression_type(
builder,
comparison_expression,
scalar_boolean_expression_graphql,
@ -179,14 +182,14 @@ fn build_comparable_fields_schema(
// create Field annotation for this field
let annotation = types::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: types::ModelFilterArgument::Field {
BooleanExpressionAnnotation::ObjectBooleanExpressionField(
types::ObjectBooleanExpressionField::Field {
field_name: field_name.clone(),
object_field_kind: ObjectFieldKind::Scalar,
object_type: object_type_name.clone(),
deprecated: field_definition.deprecated.clone(),
},
},
),
));
// calculate permissions
@ -253,17 +256,17 @@ fn build_comparable_fields_schema(
// create Field annotation for field
let annotation = types::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: types::ModelFilterArgument::Field {
BooleanExpressionAnnotation::ObjectBooleanExpressionField(
types::ObjectBooleanExpressionField::Field {
field_name: field_name.clone(),
object_field_kind: match object_comparison_expression.field_kind {
ObjectComparisonKind::Object => ObjectFieldKind::Object,
ObjectComparisonKind::Array => ObjectFieldKind::Array,
ObjectComparisonKind::ObjectArray => ObjectFieldKind::ObjectArray,
},
object_type: object_type_name.clone(),
deprecated: field_definition.deprecated.clone(),
},
},
),
));
// calculate permissions
@ -564,9 +567,9 @@ fn build_model_relationship_schema(
relationship.field_name.clone(),
None,
types::Annotation::Input(InputAnnotation::BooleanExpression(
BooleanExpressionAnnotation::BooleanExpressionArgument {
field: types::ModelFilterArgument::RelationshipField(annotation),
},
BooleanExpressionAnnotation::ObjectBooleanExpressionField(
types::ObjectBooleanExpressionField::RelationshipField(annotation),
),
)),
ast::TypeContainer::named_null(gql_schema::RegisteredTypeName::new(
target_filter_expression_graphql_type.0.clone(),
@ -691,7 +694,7 @@ fn build_schema_with_boolean_expression_type(
}
}
fn get_scalar_comparison_input_type(
fn get_scalar_boolean_expression_type(
builder: &mut gql_schema::Builder<GDS>,
comparison_expression: &metadata_resolve::ComparisonExpressionInfo,
scalar_boolean_expression_graphql: &metadata_resolve::ScalarBooleanExpressionGraphqlConfig,
@ -706,7 +709,7 @@ fn get_scalar_comparison_input_type(
operators.push((op_name, input_type.clone()));
}
Ok(
builder.register_type(TypeId::ScalarTypeComparisonExpression {
builder.register_type(TypeId::InputScalarBooleanExpressionType {
graphql_type_name,
operators,
operator_mapping: comparison_expression.operator_mapping.clone(),
@ -726,3 +729,90 @@ fn include_relationship_field(
// Else, check for NDC capability
|| target_capabilities.is_some_and(|capabilities| capabilities.supports_relationships.as_ref().is_some_and(|r| r.supports_relation_comparisons))
}
pub fn build_scalar_boolean_expression_input(
gds: &GDS,
builder: &mut gql_schema::Builder<GDS>,
type_name: &ast::TypeName,
operators: &Vec<(ast::Name, QualifiedTypeReference)>,
operator_mapping: &BTreeMap<Qualified<DataConnectorName>, OperatorMapping>,
maybe_is_null_operator_name: &Option<ast::Name>,
) -> Result<gql_schema::TypeInfo<GDS>, Error> {
let mut input_fields: BTreeMap<
ast::Name,
gql_schema::Namespaced<GDS, gql_schema::InputField<GDS>>,
> = BTreeMap::new();
if let Some(is_null_operator_name) = maybe_is_null_operator_name {
// Add is_null field
let is_null_input_type = ast::TypeContainer {
base: ast::BaseTypeContainer::Named(gql_schema::RegisteredTypeName::boolean()),
nullable: true,
};
input_fields.insert(
is_null_operator_name.clone(),
builder.allow_all_namespaced(gql_schema::InputField::new(
is_null_operator_name.clone(),
None,
types::Annotation::Input(types::InputAnnotation::BooleanExpression(
types::BooleanExpressionAnnotation::ScalarBooleanExpressionField(
types::ScalarBooleanExpressionField::IsNullOperation,
),
)),
is_null_input_type,
None,
gql_schema::DeprecationStatus::NotDeprecated,
)),
);
}
for (op_name, input_type) in operators {
// comparison_operator: input_type
let input_type = input_type::get_input_type(gds, builder, input_type)?;
// Presence of all scalar fields in the comparison expression is not compulsory. Users can filter rows based on
// scalar fields of their choice. Hence, the input type of each scalar field is nullable.
let nullable_input_type = ast::TypeContainer {
base: input_type.base,
nullable: true,
};
// this feels a bit loose, we're depending on the fact the ast::Name and
// OperatorName should be the same
let operator_name = open_dds::types::OperatorName::new(op_name.as_str().into());
// for each set of mappings, only return the mapping we actually need
// default to existing mapping where one is missing
let this_operator_mapping = operator_mapping
.iter()
.map(|(data_connector_name, mappings)| {
(
data_connector_name.clone(),
mappings.get(&operator_name).clone(),
)
})
.collect();
input_fields.insert(
op_name.clone(),
builder.allow_all_namespaced(gql_schema::InputField::new(
op_name.clone(),
None,
types::Annotation::Input(types::InputAnnotation::BooleanExpression(
types::BooleanExpressionAnnotation::ScalarBooleanExpressionField(
types::ScalarBooleanExpressionField::ComparisonOperation {
operator_mapping: this_operator_mapping,
},
),
)),
nullable_input_type,
None,
gql_schema::DeprecationStatus::NotDeprecated,
)),
);
}
Ok(gql_schema::TypeInfo::InputObject(
gql_schema::InputObject::new(type_name.clone(), None, input_fields, Vec::new()),
))
}

View File

@ -40,9 +40,10 @@ pub use types::output_type::relationship::{
};
pub use types::{
Annotation, ApolloFederationRootFields, BooleanExpressionAnnotation, CommandSourceDetail,
EntityFieldTypeNameMapping, GlobalID, InputAnnotation, ModelFilterArgument,
ModelInputAnnotation, ModelOrderByDirection, NamespaceAnnotation, NodeFieldTypeNameMapping,
ObjectFieldKind, OutputAnnotation, RootFieldAnnotation, RootFieldKind, TypeKind,
EntityFieldTypeNameMapping, GlobalID, InputAnnotation, ModelInputAnnotation,
ModelOrderByDirection, NamespaceAnnotation, NodeFieldTypeNameMapping,
ObjectBooleanExpressionField, ObjectFieldKind, OutputAnnotation, RootFieldAnnotation,
RootFieldKind, ScalarBooleanExpressionField, TypeKind,
};
/// This 'NamespacedGetter' looks up 'NamespacedNodeInfo's according to actual roles.
@ -190,12 +191,12 @@ impl gql_schema::SchemaContext for GDS {
} => model_arguments::build_model_arguments_input_schema(
self, builder, type_name, model_name,
),
types::TypeId::ScalarTypeComparisonExpression {
types::TypeId::InputScalarBooleanExpressionType {
graphql_type_name,
operators,
operator_mapping,
is_null_operator_name,
} => model_filter::build_scalar_comparison_input(
} => boolean_expression::build_scalar_boolean_expression_input(
self,
builder,
graphql_type_name,

View File

@ -1,16 +1,12 @@
use super::types::input_type;
use lang_graphql::ast::common as ast;
use lang_graphql::schema::{self as gql_schema, InputField, Namespaced};
use open_dds::{data_connector::DataConnectorName, types::CustomTypeName};
use std::collections::BTreeMap;
use lang_graphql::schema::{self as gql_schema};
use open_dds::types::CustomTypeName;
use metadata_resolve::{OperatorMapping, Qualified, QualifiedTypeReference};
use metadata_resolve::Qualified;
use crate::types;
use crate::GDS;
use crate::Error;
pub fn get_where_expression_input_field(
builder: &mut gql_schema::Builder<GDS>,
gds_type_name: Qualified<CustomTypeName>,
@ -23,7 +19,7 @@ pub fn get_where_expression_input_field(
.clone(),
None,
types::Annotation::Input(types::InputAnnotation::BooleanExpression(
types::BooleanExpressionAnnotation::BooleanExpression,
types::BooleanExpressionAnnotation::BooleanExpressionRootField,
)),
ast::TypeContainer::named_null(builder.register_type(
types::TypeId::InputObjectBooleanExpressionType {
@ -35,83 +31,3 @@ pub fn get_where_expression_input_field(
gql_schema::DeprecationStatus::NotDeprecated,
)
}
pub fn build_scalar_comparison_input(
gds: &GDS,
builder: &mut gql_schema::Builder<GDS>,
type_name: &ast::TypeName,
operators: &Vec<(ast::Name, QualifiedTypeReference)>,
operator_mapping: &BTreeMap<Qualified<DataConnectorName>, OperatorMapping>,
maybe_is_null_operator_name: &Option<ast::Name>,
) -> Result<gql_schema::TypeInfo<GDS>, Error> {
let mut input_fields: BTreeMap<ast::Name, Namespaced<GDS, InputField<GDS>>> = BTreeMap::new();
if let Some(is_null_operator_name) = maybe_is_null_operator_name {
// Add is_null field
let is_null_input_type = ast::TypeContainer {
base: ast::BaseTypeContainer::Named(gql_schema::RegisteredTypeName::boolean()),
nullable: true,
};
input_fields.insert(
is_null_operator_name.clone(),
builder.allow_all_namespaced(gql_schema::InputField::new(
is_null_operator_name.clone(),
None,
types::Annotation::Input(types::InputAnnotation::Model(
types::ModelInputAnnotation::IsNullOperation,
)),
is_null_input_type,
None,
gql_schema::DeprecationStatus::NotDeprecated,
)),
);
}
for (op_name, input_type) in operators {
// comparison_operator: input_type
let input_type = input_type::get_input_type(gds, builder, input_type)?;
// Presence of all scalar fields in the comparison expression is not compulsory. Users can filter rows based on
// scalar fields of their choice. Hence, the input type of each scalar field is nullable.
let nullable_input_type = ast::TypeContainer {
base: input_type.base,
nullable: true,
};
// this feels a bit loose, we're depending on the fact the ast::Name and
// OperatorName should be the same
let operator_name = open_dds::types::OperatorName::new(op_name.as_str().into());
// for each set of mappings, only return the mapping we actually need
// default to existing mapping where one is missing
let this_operator_mapping = operator_mapping
.iter()
.map(|(data_connector_name, mappings)| {
(
data_connector_name.clone(),
mappings.get(&operator_name).clone(),
)
})
.collect();
input_fields.insert(
op_name.clone(),
builder.allow_all_namespaced(gql_schema::InputField::new(
op_name.clone(),
None,
types::Annotation::Input(types::InputAnnotation::Model(
types::ModelInputAnnotation::ComparisonOperation {
operator_mapping: this_operator_mapping,
},
)),
nullable_input_type,
None,
gql_schema::DeprecationStatus::NotDeprecated,
)),
);
}
Ok(gql_schema::TypeInfo::InputObject(
gql_schema::InputObject::new(type_name.clone(), None, input_fields, Vec::new()),
))
}

View File

@ -84,22 +84,7 @@ pub enum RootFieldKind {
pub enum ObjectFieldKind {
Scalar,
Object,
Array,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum ModelFilterArgument {
AndOp,
OrOp,
NotOp,
Field {
field_name: types::FieldName,
object_type: Qualified<types::CustomTypeName>,
object_field_kind: ObjectFieldKind,
/// To mark a field as deprecated in the field usage while reporting query usage analytics.
deprecated: Option<Deprecated>,
},
RelationshipField(FilterRelationshipAnnotation),
ObjectArray,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
@ -230,14 +215,6 @@ pub enum ModelInputAnnotation {
argument_kind: metadata_resolve::ArgumentKind,
ndc_table_argument: Option<DataConnectorArgumentName>,
},
ComparisonOperation {
#[serde(
serialize_with = "serialize_non_string_key_btreemap",
deserialize_with = "deserialize_non_string_key_btreemap"
)]
operator_mapping: BTreeMap<Qualified<DataConnectorName>, DataConnectorOperatorName>,
},
IsNullOperation,
ModelOrderByExpression,
ModelOrderByNestedExpression {
ndc_column: DataConnectorColumnName,
@ -268,8 +245,41 @@ pub enum ModelInputAnnotation {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Display)]
/// Annotations of the input types/fields related to boolean expressions.
pub enum BooleanExpressionAnnotation {
BooleanExpression,
BooleanExpressionArgument { field: ModelFilterArgument },
/// Marks the field that contains the root of the boolean expression. eg. a "where" field
BooleanExpressionRootField,
/// Marks a field inside an object boolean expression
ObjectBooleanExpressionField(ObjectBooleanExpressionField),
/// Marks a field inside an scalar boolean expression
ScalarBooleanExpressionField(ScalarBooleanExpressionField),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum ObjectBooleanExpressionField {
AndOp,
OrOp,
NotOp,
Field {
field_name: types::FieldName,
object_type: Qualified<types::CustomTypeName>,
object_field_kind: ObjectFieldKind,
/// To mark a field as deprecated in the field usage while reporting query usage analytics.
deprecated: Option<Deprecated>,
},
RelationshipField(FilterRelationshipAnnotation),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum ScalarBooleanExpressionField {
ComparisonOperation {
#[serde(
serialize_with = "serialize_non_string_key_btreemap",
deserialize_with = "deserialize_non_string_key_btreemap"
)]
operator_mapping: BTreeMap<Qualified<DataConnectorName>, DataConnectorOperatorName>,
},
IsNullOperation,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Display)]
@ -385,6 +395,12 @@ pub enum TypeId {
gds_type_name: Qualified<types::CustomTypeName>,
graphql_type_name: ast::TypeName,
},
InputScalarBooleanExpressionType {
graphql_type_name: ast::TypeName,
operators: Vec<(ast::Name, QualifiedTypeReference)>,
operator_mapping: BTreeMap<Qualified<DataConnectorName>, OperatorMapping>,
is_null_operator_name: Option<ast::Name>,
},
NodeRoot,
ModelArgumentsInput {
model_name: Qualified<models::ModelName>,
@ -395,12 +411,6 @@ pub enum TypeId {
order_by_expression_identifier: Qualified<OrderByExpressionIdentifier>,
graphql_type_name: ast::TypeName,
},
ScalarTypeComparisonExpression {
graphql_type_name: ast::TypeName,
operators: Vec<(ast::Name, QualifiedTypeReference)>,
operator_mapping: BTreeMap<Qualified<DataConnectorName>, OperatorMapping>,
is_null_operator_name: Option<ast::Name>,
},
OrderByEnumType {
graphql_type_name: ast::TypeName,
},
@ -447,7 +457,7 @@ impl TypeId {
| TypeId::InputObjectBooleanExpressionType {
graphql_type_name, ..
}
| TypeId::ScalarTypeComparisonExpression {
| TypeId::InputScalarBooleanExpressionType {
graphql_type_name, ..
}
| TypeId::ModelOrderByExpression {

View File

@ -66,7 +66,7 @@ pub(crate) fn validate_data_connector_with_object_boolean_expression_type(
}));
}
}
boolean_expressions::ObjectComparisonKind::Array => {
boolean_expressions::ObjectComparisonKind::ObjectArray => {
// raise a warning if our data connector does not support filtering nested arrays
if !data_connector.capabilities.supports_nested_array_filtering {
issues.push(

View File

@ -83,7 +83,7 @@ pub(crate) fn resolve_object_boolean_graphql(
}
}
}
ComparableFieldKind::Object | ComparableFieldKind::Array => {
ComparableFieldKind::Object | ComparableFieldKind::ObjectArray => {
// if this field isn't a scalar, let's see if it's an object instead
let (_field_subgraph, raw_boolean_expression_type) =
helpers::lookup_raw_boolean_expression(

View File

@ -269,7 +269,7 @@ fn resolve_comparable_fields(
BooleanExpressionObjectAggregateOperand { r#type, .. },
) => {
let field_kind = match field.field_type.underlying_type {
QualifiedBaseType::List(_) => ComparableFieldKind::Array,
QualifiedBaseType::List(_) => ComparableFieldKind::ObjectArray,
QualifiedBaseType::Named(_) => ComparableFieldKind::Object,
};
(field_kind, TypeName::Custom(r#type.clone()))
@ -346,7 +346,7 @@ fn resolve_comparable_fields(
};
}
}
ComparableFieldKind::Object | ComparableFieldKind::Array => {
ComparableFieldKind::Object | ComparableFieldKind::ObjectArray => {
// if this field isn't a scalar, let's see if it's an object instead
let (field_subgraph, raw_boolean_expression_type) =
helpers::lookup_raw_boolean_expression(
@ -362,7 +362,9 @@ fn resolve_comparable_fields(
comparable_field_name.clone(),
ObjectComparisonExpressionInfo {
field_kind: match comparable_field_kind {
ComparableFieldKind::Array => ObjectComparisonKind::Array,
ComparableFieldKind::ObjectArray => {
ObjectComparisonKind::ObjectArray
}
ComparableFieldKind::Object => ObjectComparisonKind::Object,
ComparableFieldKind::Scalar => unreachable!(),
},

View File

@ -73,7 +73,7 @@ pub struct BooleanExpressionsOutput {
pub enum ComparableFieldKind {
Scalar,
Object,
Array,
ObjectArray,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
@ -154,7 +154,7 @@ pub struct ComparisonExpressionInfo {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum ObjectComparisonKind {
Object,
Array,
ObjectArray,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]