|
| 1 | +#if INTERACTIVE |
| 2 | +#I @"../../bin/lib/net48/" |
| 3 | +#r "FSharp.Data.SqlProvider.Common.dll" |
| 4 | +#r "FSharp.Data.SqlProvider.dll" |
| 5 | +#r @"../../packages/tests/NUnit/lib/netstandard2.0/nunit.framework.dll" |
| 6 | +#else |
| 7 | +module AdvancedQueryTests |
| 8 | +#endif |
| 9 | + |
| 10 | +open System |
| 11 | +open FSharp.Data.Sql |
| 12 | +open System.Linq |
| 13 | +open NUnit.Framework |
| 14 | + |
| 15 | +[<Literal>] |
| 16 | +let connectionString = @"Data Source=" + __SOURCE_DIRECTORY__ + @"/../db/northwindEF.db;Version=3;Read Only=false;FailIfMissing=True;" |
| 17 | + |
| 18 | +[<Literal>] |
| 19 | +let resolutionPath = __SOURCE_DIRECTORY__ + "/../libs" |
| 20 | + |
| 21 | +// If you want to run these in Visual Studio Test Explorer, please install: |
| 22 | +// Tools -> Extensions and Updates... -> Online -> NUnit Test Adapter for Visual Studio |
| 23 | +// http://nunit.org/index.php?p=vsTestAdapter&r=2.6.4 |
| 24 | + |
| 25 | +type sql = SqlDataProvider<Common.DatabaseProviderTypes.SQLITE, connectionString, CaseSensitivityChange=Common.CaseSensitivityChange.ORIGINAL, ResolutionPath = resolutionPath, SQLiteLibrary=Common.SQLiteLibrary.SystemDataSQLite> |
| 26 | +FSharp.Data.Sql.Common.QueryEvents.SqlQueryEvent |> Event.add (printfn "Executing SQL: %O") |
| 27 | +type sqlOpt = SqlDataProvider<Common.DatabaseProviderTypes.SQLITE, connectionString, CaseSensitivityChange=Common.CaseSensitivityChange.ORIGINAL, ResolutionPath = resolutionPath, SQLiteLibrary=Common.SQLiteLibrary.SystemDataSQLite, UseOptionTypes = Common.NullableColumnType.VALUE_OPTION> |
| 28 | + |
| 29 | +//[<SetUp>] |
| 30 | +//let setUp() = |
| 31 | +// let ctx = sql.GetDataContext() |
| 32 | +// // Setup test data |
| 33 | +// () |
| 34 | + |
| 35 | +[<Test>] |
| 36 | +let ``complex join with navigation properties`` () = |
| 37 | + let ctx = sql.GetDataContext() |
| 38 | + let query = |
| 39 | + query { |
| 40 | + for customer in ctx.Main.Customers do |
| 41 | + for order in customer.``main.Orders by CustomerID`` do |
| 42 | + for detail in order.``main.OrderDetails by OrderID`` do |
| 43 | + where (detail.Quantity > (int16 10)) |
| 44 | + select (customer.CompanyName, order.OrderDate, detail.Quantity) |
| 45 | + } |
| 46 | + |
| 47 | + let results = query |> Seq.toList |
| 48 | + Assert.IsNotEmpty(results) |
| 49 | + |
| 50 | +[<Test>] |
| 51 | +let ``subquery with exists pattern`` () = |
| 52 | + let ctx = sql.GetDataContext() |
| 53 | + |
| 54 | + // Find customers who have orders with expensive items |
| 55 | + let expensiveOrderCustomers = |
| 56 | + query { |
| 57 | + for customer in ctx.Main.Customers do |
| 58 | + where (query { |
| 59 | + for order in ctx.Main.Orders do |
| 60 | + join detail in ctx.Main.OrderDetails on (order.OrderId = detail.OrderId) |
| 61 | + exists (order.CustomerId = customer.CustomerId && detail.UnitPrice > 50m) |
| 62 | + }) |
| 63 | + select customer.CustomerId |
| 64 | + } |
| 65 | + |
| 66 | + let results = expensiveOrderCustomers |> Seq.toList |
| 67 | + Assert.IsNotEmpty(results) |
| 68 | + |
| 69 | +[<Test>] |
| 70 | +let ``complex aggregation with grouping`` () = |
| 71 | + let ctx = sql.GetDataContext() |
| 72 | + |
| 73 | + let orderStats = |
| 74 | + query { |
| 75 | + for order in ctx.Main.Orders do |
| 76 | + join detail in ctx.Main.OrderDetails on (order.OrderId = detail.OrderId) |
| 77 | + groupBy order.CustomerId into g |
| 78 | + select (g.Key, |
| 79 | + g.Count(), |
| 80 | + g.Sum(fun (_,x) -> x.UnitPrice * decimal x.Quantity), |
| 81 | + g.Average(fun (_,x) -> x.UnitPrice)) |
| 82 | + } |
| 83 | + |
| 84 | + let results = orderStats |> Seq.toList |
| 85 | + Assert.IsNotEmpty(results) |
| 86 | + |
| 87 | +[<Test>] |
| 88 | +let ``option type handling with ValueSome pattern`` () = |
| 89 | + let ctx = sqlOpt.GetDataContext() |
| 90 | + |
| 91 | + let customersWithRegion = |
| 92 | + query { |
| 93 | + for customer in ctx.Main.Customers do |
| 94 | + where (customer.Region.IsSome) |
| 95 | + select (customer.CompanyName, customer.Region.Value) |
| 96 | + } |
| 97 | + |
| 98 | + let results = customersWithRegion |> Seq.toList |
| 99 | + Assert.IsNotEmpty(results) |
| 100 | + |
| 101 | +[<Test>] |
| 102 | +let ``pagination with complex sorting`` () = |
| 103 | + let ctx = sql.GetDataContext() |
| 104 | + let pageSize = 10 |
| 105 | + let pageNumber = 1 |
| 106 | + |
| 107 | + let pagedResults = |
| 108 | + query { |
| 109 | + for customer in ctx.Main.Customers do |
| 110 | + sortBy customer.Country |
| 111 | + thenBy customer.City |
| 112 | + thenByDescending customer.CompanyName |
| 113 | + skip ((pageNumber - 1) * pageSize) |
| 114 | + take pageSize |
| 115 | + select customer |
| 116 | + } |
| 117 | + |
| 118 | + let results = pagedResults |> Seq.toList |
| 119 | + Assert.LessOrEqual(results.Length, pageSize) |
| 120 | + |
| 121 | + |
| 122 | +[<Test>] |
| 123 | +let ``dynamic filtering with multiple optional parameters`` () = |
| 124 | + let ctx = sql.GetDataContext() |
| 125 | + |
| 126 | + let searchCustomers (country: string option) (city: string option) (hasOrders: bool) = |
| 127 | + let noCountry, country = match country with | None -> true, "" | Some x -> false, x |
| 128 | + let noCity, city = match city with | None -> true, "" | Some x -> false, x |
| 129 | + |
| 130 | + query { |
| 131 | + for customer in ctx.Main.Customers do |
| 132 | + where ( |
| 133 | + (noCountry || customer.Country = country) && |
| 134 | + (noCity || customer.City = city) && |
| 135 | + (hasOrders || |
| 136 | + (query { |
| 137 | + for order in ctx.Main.Orders do |
| 138 | + exists (order.CustomerId = customer.CustomerId) |
| 139 | + })) |
| 140 | + ) |
| 141 | + select customer |
| 142 | + } |
| 143 | + |
| 144 | + let results1 = searchCustomers (Some "USA") None false |> Seq.toList |
| 145 | + let results2 = searchCustomers None (Some "London") true |> Seq.toList |
| 146 | + |
| 147 | + Assert.IsNotEmpty(results1) |
| 148 | + Assert.IsNotEmpty(results2) |
| 149 | + |
| 150 | +[<Test>] |
| 151 | +let ``complex case when expression`` () = |
| 152 | + let ctx = sql.GetDataContext() |
| 153 | + |
| 154 | + let customerCategories = |
| 155 | + query { |
| 156 | + for customer in ctx.Main.Customers do |
| 157 | + select ( |
| 158 | + customer.CompanyName, |
| 159 | + (query { |
| 160 | + for order in ctx.Main.Orders do |
| 161 | + where (order.CustomerId = customer.CustomerId) |
| 162 | + count |
| 163 | + } |> fun count -> |
| 164 | + if count > 10 then "High Volume" |
| 165 | + elif count > 5 then "Medium Volume" |
| 166 | + else "Low Volume") |
| 167 | + ) |
| 168 | + } |
| 169 | + |
| 170 | + let results = customerCategories |> Seq.toList |
| 171 | + Assert.IsNotEmpty(results) |
| 172 | + |
0 commit comments