Skip to content

Commit af25547

Browse files
author
Viktor Tochonov
committed
Implemented ObjectListFilter tests for And, Or, Not filters and supplying filter from variables
1 parent 48bb152 commit af25547

File tree

3 files changed

+223
-13
lines changed

3 files changed

+223
-13
lines changed

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,14 @@ query TestQuery {
354354
appearsIn
355355
homePlanet
356356
friends (filter : { name_starts_with: "A" }) {
357-
friends (filter : { or : { name_starts_with: "A", name_starts_with: "B" }}) {
358357
id
359358
name
360359
}
361360
}
362361
}
363362
```
364363

365-
Also you can apply `not` operator and combine filters with `and` and `or` operators like this:
364+
Also you can apply `not` operator like this:
366365

367366
```graphql
368367
query TestQuery {
@@ -371,7 +370,24 @@ query TestQuery {
371370
name
372371
appearsIn
373372
homePlanet
374-
friends (filter : { or : { name_starts_with: "A", name_starts_with: "B" }}) {
373+
friends (filter : { not : { name_starts_with: "A" } }) {
374+
id
375+
name
376+
}
377+
}
378+
}
379+
```
380+
381+
And combine filters with `and` and `or` operators like this:
382+
383+
```graphql
384+
query TestQuery {
385+
hero(id:"1000") {
386+
id
387+
name
388+
appearsIn
389+
homePlanet
390+
friends (filter : { or : [{ name_starts_with: "A"}, { name_starts_with: "B" }]}) {
375391
id
376392
name
377393
}

src/FSharp.Data.GraphQL.Server.Middleware/MiddlewareDefinitions.fs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ open System.Collections.Immutable
55
open FsToolkit.ErrorHandling
66

77
open FSharp.Data.GraphQL
8+
open FSharp.Data.GraphQL.Ast
89
open FSharp.Data.GraphQL.Types.Patterns
910
open FSharp.Data.GraphQL.Types
1011

@@ -90,8 +91,9 @@ type internal ObjectListFilterMiddleware<'ObjectType, 'ListType>(reportToMetadat
9091
let filterResults =
9192
field.Ast.Arguments
9293
|> Seq.map (fun x ->
93-
match x.Name with
94-
| "filter" -> ObjectListFilter.CoerceInput (InlineConstant x.Value)
94+
match x.Name, x.Value with
95+
| "filter", (VariableName variableName) -> Ok (ctx.Variables[variableName] :?> ObjectListFilter)
96+
| "filter", inlineConstant -> ObjectListFilter.CoerceInput (InlineConstant inlineConstant)
9597
| _ -> Ok NoFilter)
9698
|> Seq.toList
9799
match filterResults |> splitSeqErrorsList with

tests/FSharp.Data.GraphQL.Tests/MiddlewareTests.fs

Lines changed: 200 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ open FSharp.Data.GraphQL.Shared
1010
open FSharp.Data.GraphQL.Parser
1111
open FSharp.Data.GraphQL.Execution
1212
open FSharp.Data.GraphQL.Ast
13+
open System.Collections.Immutable
14+
open System.Text.Json
1315

1416
#nowarn "40"
1517

@@ -87,14 +89,16 @@ let executor =
8789
Define.ObjectListFilterMiddleware<B, Subject option>(true) ]
8890
Executor(schema, middleware)
8991

92+
let executeWithVariables (query : Document , variables: ImmutableDictionary<string, JsonElement>) =
93+
executor.AsyncExecute(ast = query, variables = variables) |> sync
9094
let execute (query : Document) =
9195
executor.AsyncExecute(query) |> sync
9296

9397
let expectedErrors : GQLProblemDetails list =
9498
[ GQLProblemDetails.Create ("Query complexity exceeds maximum threshold. Please reduce query complexity and try again.") ]
9599

96100
[<Fact>]
97-
let ``Simple query: Should pass when below threshold``() =
101+
let ``Simple query: Must pass when below threshold``() =
98102
let query =
99103
parse """query testQuery {
100104
A (id : 1) {
@@ -141,7 +145,7 @@ let ``Simple query: Should pass when below threshold``() =
141145
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 1.0)
142146

143147
[<Fact>]
144-
let ``Simple query: Should not pass when above threshold``() =
148+
let ``Simple query: Must not pass when above threshold``() =
145149
let query =
146150
parse """query testQuery {
147151
A (id : 1) {
@@ -198,7 +202,7 @@ let ``Simple query: Should not pass when above threshold``() =
198202
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 3.0)
199203

200204
[<Fact>]
201-
let ``Deferred queries : Should pass when below threshold``() =
205+
let ``Deferred queries : Must pass when below threshold``() =
202206
let query =
203207
parse """query testQuery {
204208
A (id : 1) {
@@ -251,7 +255,7 @@ let ``Deferred queries : Should pass when below threshold``() =
251255
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 2.0)
252256

253257
[<Fact>]
254-
let ``Streamed queries : Should pass when below threshold``() =
258+
let ``Streamed queries : Must pass when below threshold``() =
255259
let query =
256260
parse """query testQuery {
257261
A (id : 1) {
@@ -312,7 +316,7 @@ let ``Streamed queries : Should pass when below threshold``() =
312316
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 2.0)
313317

314318
[<Fact>]
315-
let ``Deferred and Streamed queries : Should not pass when above threshold``() =
319+
let ``Deferred and Streamed queries : Must not pass when above threshold``() =
316320
let query =
317321
sprintf """query testQuery {
318322
A (id : 1) {
@@ -371,7 +375,7 @@ let ``Deferred and Streamed queries : Should not pass when above threshold``() =
371375
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 3.0))
372376

373377
[<Fact>]
374-
let ``Inline fragment query : Should pass when below threshold``() =
378+
let ``Inline fragment query : Must pass when below threshold``() =
375379
let query =
376380
parse """query testQuery {
377381
A (id : 1) {
@@ -412,7 +416,7 @@ let ``Inline fragment query : Should pass when below threshold``() =
412416
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 1.0)
413417

414418
[<Fact>]
415-
let ``Inline fragment query : Should not pass when above threshold``() =
419+
let ``Inline fragment query : Must not pass when above threshold``() =
416420
let query =
417421
parse """query testQuery {
418422
A (id : 1) {
@@ -465,7 +469,7 @@ let ``Inline fragment query : Should not pass when above threshold``() =
465469
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 3.0)
466470

467471
[<Fact>]
468-
let ``Object list filter: should return filter information in Metadata``() =
472+
let ``Object list filter: must return filter information in Metadata``() =
469473
let query =
470474
parse """query testQuery {
471475
A (id : 1) {
@@ -511,3 +515,191 @@ let ``Object list filter: should return filter information in Metadata``() =
511515
result.Metadata.TryFind<float>("queryWeightThreshold") |> equals (ValueSome 2.0)
512516
result.Metadata.TryFind<float>("queryWeight") |> equals (ValueSome 1.0)
513517
result.Metadata.TryFind<ObjectListFilters>("filters") |> wantValueSome |> seqEquals [ expectedFilter ]
518+
519+
[<Fact>]
520+
let ``Object list filter: Must return AND filter information in Metadata``() =
521+
let query =
522+
parse """query testQuery {
523+
A (id : 1) {
524+
id
525+
value
526+
subjects (filter : { and : [{ value_starts_with: "3"}, {id : 6 }]}) { ...Value }
527+
}
528+
}
529+
530+
fragment Value on Subject {
531+
...on A {
532+
id
533+
value
534+
}
535+
...on B {
536+
id
537+
value
538+
}
539+
}"""
540+
let expected =
541+
NameValueLookup.ofList [
542+
"A", upcast NameValueLookup.ofList [
543+
"id", upcast 1
544+
"value", upcast "A1"
545+
"subjects", upcast [
546+
NameValueLookup.ofList [
547+
"id", upcast 2
548+
"value", upcast "A2"
549+
]
550+
NameValueLookup.ofList [
551+
"id", upcast 6
552+
"value", upcast "3000"
553+
]
554+
]
555+
]
556+
]
557+
let expectedFilter : KeyValuePair<obj list, ObjectListFilter> =
558+
KeyValuePair(["A"; "subjects"], And (StartsWith { FieldName = "value"; Value = "3" }, Equals { FieldName = "id"; Value = 6L }))
559+
let result = execute query
560+
ensureDirect result <| fun data errors ->
561+
empty errors
562+
data |> equals (upcast expected)
563+
result.Metadata.TryFind<ObjectListFilters>("filters") |> wantValueSome |> seqEquals [ expectedFilter ]
564+
565+
[<Fact>]
566+
let ``Object list filter: Must return OR filter information in Metadata``() =
567+
let query =
568+
parse """query testQuery {
569+
A (id : 1) {
570+
id
571+
value
572+
subjects (filter : { or : [{value_starts_with: "3"}, {id : 6}] }) { ...Value }
573+
}
574+
}
575+
576+
fragment Value on Subject {
577+
...on A {
578+
id
579+
value
580+
}
581+
...on B {
582+
id
583+
value
584+
}
585+
}"""
586+
let expected =
587+
NameValueLookup.ofList [
588+
"A", upcast NameValueLookup.ofList [
589+
"id", upcast 1
590+
"value", upcast "A1"
591+
"subjects", upcast [
592+
NameValueLookup.ofList [
593+
"id", upcast 2
594+
"value", upcast "A2"
595+
]
596+
NameValueLookup.ofList [
597+
"id", upcast 6
598+
"value", upcast "3000"
599+
]
600+
]
601+
]
602+
]
603+
let expectedFilter : KeyValuePair<obj list, ObjectListFilter> =
604+
KeyValuePair(["A"; "subjects"], Or (StartsWith { FieldName = "value"; Value = "3" }, Equals { FieldName = "id"; Value = 6L }))
605+
let result = execute query
606+
ensureDirect result <| fun data errors ->
607+
empty errors
608+
data |> equals (upcast expected)
609+
result.Metadata.TryFind<ObjectListFilters>("filters") |> wantValueSome |> seqEquals [ expectedFilter ]
610+
611+
[<Fact>]
612+
let ``Object list filter: Must return NOT filter information in Metadata``() =
613+
let query =
614+
parse """query testQuery {
615+
A (id : 1) {
616+
id
617+
value
618+
subjects (filter : { not : {value_starts_with: "3"} }) { ...Value }
619+
}
620+
}
621+
622+
fragment Value on Subject {
623+
...on A {
624+
id
625+
value
626+
}
627+
...on B {
628+
id
629+
value
630+
}
631+
}"""
632+
let expected =
633+
NameValueLookup.ofList [
634+
"A", upcast NameValueLookup.ofList [
635+
"id", upcast 1
636+
"value", upcast "A1"
637+
"subjects", upcast [
638+
NameValueLookup.ofList [
639+
"id", upcast 2
640+
"value", upcast "A2"
641+
]
642+
NameValueLookup.ofList [
643+
"id", upcast 6
644+
"value", upcast "3000"
645+
]
646+
]
647+
]
648+
]
649+
let expectedFilter : KeyValuePair<obj list, ObjectListFilter> =
650+
KeyValuePair(["A"; "subjects"], Not (StartsWith { FieldName = "value"; Value = "3" }))
651+
let result = execute query
652+
ensureDirect result <| fun data errors ->
653+
empty errors
654+
data |> equals (upcast expected)
655+
result.Metadata.TryFind<ObjectListFilters>("filters") |> wantValueSome |> seqEquals [ expectedFilter ]
656+
657+
[<Fact>]
658+
let ``Object list filter: Must return filter information in Metadata when supplied as variable``() =
659+
let jsonString = """{ "not": { "value_starts_with": "3" } }"""
660+
let jsonElement = JsonDocument.Parse(jsonString).RootElement
661+
662+
let dict = ImmutableDictionary<string, JsonElement>.Empty.Add("filter", jsonElement)
663+
let query =
664+
parse """query testQuery($filter: ObjectListFilter!) {
665+
A (id : 1) {
666+
id
667+
value
668+
subjects (filter : $filter) { ...Value }
669+
}
670+
}
671+
672+
fragment Value on Subject {
673+
...on A {
674+
id
675+
value
676+
}
677+
...on B {
678+
id
679+
value
680+
}
681+
}"""
682+
let expected =
683+
NameValueLookup.ofList [
684+
"A", upcast NameValueLookup.ofList [
685+
"id", upcast 1
686+
"value", upcast "A1"
687+
"subjects", upcast [
688+
NameValueLookup.ofList [
689+
"id", upcast 2
690+
"value", upcast "A2"
691+
]
692+
NameValueLookup.ofList [
693+
"id", upcast 6
694+
"value", upcast "3000"
695+
]
696+
]
697+
]
698+
]
699+
let expectedFilter : KeyValuePair<obj list, ObjectListFilter> =
700+
KeyValuePair(["A"; "subjects"], Not (StartsWith { FieldName = "value"; Value = "3" }))
701+
let result = executeWithVariables(query, dict)
702+
ensureDirect result <| fun data errors ->
703+
empty errors
704+
data |> equals (upcast expected)
705+
result.Metadata.TryFind<ObjectListFilters>("filters") |> wantValueSome |> seqEquals [ expectedFilter ]

0 commit comments

Comments
 (0)