Skip to content

Implemented tests for scalar wrappers #524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<PackageReference Update="GraphQL.Server.Ui.Voyager" Version="8.*" />
<PackageReference Update="HotChocolate.AspNetCore" Version="15.*" />
<PackageReference Update="Iced" Version="1.17.*" />
<PackageReference Update="Microsoft.Azure.Cosmos" Version="3.*" />
<PackageReference Update="Microsoft.CodeCoverage" Version="17.3.*" />
<PackageReference Update="Microsoft.Data.Sqlite" Version="$(MicrosoftExtensionsVersion)" />
<PackageReference Update="Microsoft.Diagnostics.NETCore.Client" Version="0.2.*" />
Expand Down
32 changes: 29 additions & 3 deletions src/FSharp.Data.GraphQL.Server.Middleware/ObjectListFilter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ module ObjectListFilter =
let private StringStartsWithMethod = typeof<string>.GetMethod ("StartsWith", [| typeof<string> |])
let private StringEndsWithMethod = typeof<string>.GetMethod ("EndsWith", [| typeof<string> |])
let private StringContainsMethod = typeof<string>.GetMethod ("Contains", [| typeof<string> |])
let private MemberStartsWithMethod (memberType : Type) =
match memberType.GetMethod ("StartsWith", [| memberType |]) with
| null -> raise (MissingMemberException $"Method 'StartsWith' not found on '{memberType.FullName}'")
| method -> method
let private MemberEndsWithMethod (memberType : Type) =
match memberType.GetMethod ("EndsWith", [| memberType |]) with
| null -> raise (MissingMemberException $"Method 'EndsWith' not found on '{memberType.FullName}'")
| method -> method
let private MemberContainsMethod (memberType : Type) =
match memberType.GetMethod ("Contains", [| memberType |]) with
| null -> raise (MissingMemberException $"Method 'Contains' not found on '{memberType.FullName}'")
| method -> method
let private getEnumerableContainsMethod (memberType : Type) =
match
typeof<Enumerable>
Expand Down Expand Up @@ -183,8 +195,18 @@ module ObjectListFilter =
| LessThan f -> Expression.LessThan (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| GreaterThanOrEqual f -> Expression.GreaterThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| LessThanOrEqual f -> Expression.LessThanOrEqual (Expression.PropertyOrField (param, f.FieldName), Expression.Constant (f.Value))
| StartsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringStartsWithMethod, Expression.Constant (f.Value))
| EndsWith f -> Expression.Call (Expression.PropertyOrField (param, f.FieldName), StringEndsWithMethod, Expression.Constant (f.Value))
| StartsWith f ->
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
if ``member``.Type = typeof<string> then
Expression.Call (``member``, StringStartsWithMethod, Expression.Constant (f.Value))
else
Expression.Call (``member``, MemberStartsWithMethod ``member``.Type, Expression.Constant (f.Value))
| EndsWith f ->
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
if ``member``.Type = typeof<string> then
Expression.Call (``member``, StringEndsWithMethod, Expression.Constant (f.Value))
else
Expression.Call (``member``, MemberEndsWithMethod ``member``.Type, Expression.Constant (f.Value))
| Contains f ->
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
let isEnumerable (memberType : Type) =
Expand Down Expand Up @@ -214,7 +236,11 @@ module ObjectListFilter =
Expression.PropertyOrField (param, f.FieldName),
Expression.Constant (f.Value)
)
| _ -> Expression.Call (``member``, StringContainsMethod, Expression.Constant (f.Value))
| _ ->
if ``member``.Type = typeof<string> then
Expression.Call (``member``, StringContainsMethod, Expression.Constant (f.Value))
else
Expression.Call (``member``, MemberContainsMethod ``member``.Type, Expression.Constant (f.Value))
| In f ->
let ``member`` = Expression.PropertyOrField (param, f.FieldName)
f.Value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Cosmos" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="BenchmarkDotNet" />
<PackageReference Include="Validus" />
Expand Down Expand Up @@ -65,6 +66,7 @@
<Compile Include="Variables and Inputs\InputListTests.fs" />
<Compile Include="SelectLinqTests.fs" />
<Compile Include="ObjectListFilterLinqTests.fs" />
<Compile Include="ObjectListFilterLinqGenerateTests.fs" />
<Compile Include="DeferredTests.fs" />
<Compile Include="SubscriptionTests.fs" />
<Compile Include="MiddlewareTests.fs" />
Expand Down
120 changes: 120 additions & 0 deletions tests/FSharp.Data.GraphQL.Tests/ObjectListFilterLinqGenerateTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
module FSharp.Data.GraphQL.Tests.ObjectListFilterLinqGenerateTests

open Xunit
open System
open System.Numerics
open Microsoft.Azure.Cosmos.Linq
open Microsoft.Azure.Cosmos
open FSharp.Data.GraphQL.Shared
open FSharp.Data.GraphQL.Server.Middleware

[<Struct>]
type ValidStringStruct =
internal
| ValidStringStruct of string
static member internal op_Equality (ValidStringStruct left, ValidStringStruct right) = left = right
static member internal op_Inequality (ValidStringStruct left, ValidStringStruct right) = left <> right

static member internal op_Equality (ValidStringStruct left, right) = left = right
static member internal op_Inequality (ValidStringStruct left, right) = left <> right
static member internal op_GreaterThan (ValidStringStruct left, right) = left > right
static member internal op_GreaterThanOrEqual (ValidStringStruct left, right) = left >= right
static member internal op_LessThan (ValidStringStruct left, right) = left < right
static member internal op_LessThanOrEqual (ValidStringStruct left, right) = left <= right

// Just for demo purposes
interface IEqualityOperators<ValidStringStruct, ValidStringStruct, bool> with
static member op_Equality (ValidStringStruct left, ValidStringStruct right) = left = right
static member op_Inequality (ValidStringStruct left, ValidStringStruct right) = left <> right
interface IComparisonOperators<ValidStringStruct, ValidStringStruct, bool> with
static member op_GreaterThan (ValidStringStruct left, ValidStringStruct right) = left > right
static member op_GreaterThanOrEqual (ValidStringStruct left, ValidStringStruct right) = left >= right
static member op_LessThan (ValidStringStruct left, ValidStringStruct right) = left < right
static member op_LessThanOrEqual (ValidStringStruct left, ValidStringStruct right) = left <= right

type ValidStringObject =
internal
| ValidStringObject of string
static member internal op_Equality (ValidStringObject left, ValidStringObject right) = left = right
static member internal op_Inequality (ValidStringObject left, ValidStringObject right) = left <> right
static member internal op_Equality (ValidStringObject left, right) = left = right
static member internal op_Inequality (ValidStringObject left, right) = left <> right
static member internal op_GreaterThan (ValidStringObject left, right) = left > right
static member internal op_GreaterThanOrEqual (ValidStringObject left, right) = left >= right
static member internal op_LessThan (ValidStringObject left, right) = left < right
static member internal op_LessThanOrEqual (ValidStringObject left, right) = left <= right

// Just for demo purposes
interface IEqualityOperators<ValidStringObject, ValidStringObject, bool> with
static member op_Equality (ValidStringObject left, ValidStringObject right) = left = right
static member op_Inequality (ValidStringObject left, ValidStringObject right) = left <> right
interface IComparisonOperators<ValidStringObject, ValidStringObject, bool> with
static member op_GreaterThan (ValidStringObject left, ValidStringObject right) = left > right
static member op_GreaterThanOrEqual (ValidStringObject left, ValidStringObject right) = left >= right
static member op_LessThan (ValidStringObject left, ValidStringObject right) = left < right
static member op_LessThanOrEqual (ValidStringObject left, ValidStringObject right) = left <= right

[<Struct>]
type ValidIntStruct =
internal
| ValidIntStruct of Int64
static member internal op_Equality (ValidIntStruct left, ValidIntStruct right) = left = right
static member internal op_Inequality (ValidIntStruct left, ValidIntStruct right) = left <> right
static member internal op_GreaterThan (ValidIntStruct left, right : Int64) = left > right

type ValidIntObject =
internal
| ValidIntObject of Int64
static member internal op_Equality (ValidIntObject left, ValidIntObject right) = left = right
static member internal op_Inequality (ValidIntObject left, ValidIntObject right) = left <> right
static member internal op_GreaterThan (ValidIntObject left, right : Int64) = left > right

type FakeEntity = {
ValidStringStruct : ValidStringStruct
ValidStringObject : ValidStringObject
string : string
ValidIntStruct : ValidIntStruct
ValidIntObject : ValidIntObject
int : Int64
}

let jsonOptions = Json.getSerializerOptions Seq.empty
let cosmosClient =
let options = CosmosClientOptions(UseSystemTextJsonSerializerWithOptions = jsonOptions)
new CosmosClient ("https://localhost:8081/", "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", options)
let container = cosmosClient.GetContainer("database", "container")
let filterOptions =
ObjectListFilterLinqOptions<FakeEntity, obj>.None

[<Fact>]
let ``ObjectListFilter works with Equals operator for ValidStringStruct`` () =
let queryable = container.GetItemLinqQueryable<FakeEntity> ()
let filter = Equals { FieldName = "validStringStruct"; Value = "Jonathan"}
let filterQuery = queryable.Apply (filter, filterOptions)
let queryDefinition = CosmosLinqExtensions.ToQueryDefinition filterQuery
equals queryDefinition.QueryText """SELECT VALUE root FROM root WHERE (root["validStringStruct"] = "Jonathan")"""

[<Fact>]
let ``ObjectListFilter works with Equals operator for ValidStringObject`` () =
let filter = Equals { FieldName = "validStringObject"; Value = ValidStringObject "Jonathan" }
let queryable = container.GetItemLinqQueryable<FakeEntity> ()
let filterQuery = queryable.Apply (filter)
let queryDefinition = CosmosLinqExtensions.ToQueryDefinition filterQuery
equals queryDefinition.QueryText, """SELECT VALUE root FROM root WHERE (root["validStringObject"] = "Jonathan")"""

[<Fact>]
let ``ObjectListFilter works with GreaterThan operator for ValidIntStruct`` () =
let queryable = container.GetItemLinqQueryable<FakeEntity> ()
let filter = GreaterThan { FieldName = "validIntStruct"; Value = 6L }
let filterQuery = queryable.Apply (filter, filterOptions)
let queryDefinition = CosmosLinqExtensions.ToQueryDefinition filterQuery
equals queryDefinition.QueryText, """SELECT VALUE root FROM root WHERE (root["validIntStruct"] > 6)"""

[<Fact>]
let ``ObjectListFilter works with GreaterThan operator for ValidIntObject`` () =
let filter = GreaterThan { FieldName = "validIntObject"; Value = 6L }
let queryable = container.GetItemLinqQueryable<FakeEntity> ()
let filterQuery = queryable.Apply (filter)
let queryDefinition = CosmosLinqExtensions.ToQueryDefinition filterQuery
equals queryDefinition.QueryText, """SELECT VALUE root FROM root WHERE (root["validIntObject"] > 6)"""