-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.fs
130 lines (104 loc) · 3.3 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
open DuckDB.NET.Data
open Expecto
open Expecto.Flip
open System.IO
open Dapper
open System
module Async =
let map f computation =
async.Bind(computation, f >> async.Return)
let zip c1 c2 =
async{
let! x = Async.StartChild c1
let! y = Async.StartChild c2
let! x' = x
let! y' = y
return x', y'
}
type AsyncBuilder with
member _.BindReturn(x: Async<'t>, f) = Async.map f x
member _.MergeSources(x: Async<'t>, y: Async<'u>) = Async.zip x y
type IDatabase =
abstract OpenConnection: unit -> Async<DuckDBConnection>
type IDb = abstract Database: IDatabase
let initialiseDb (env: #IDb) = async{
let dummyRecords =
seq{for i in 1 .. 100000 do
$"sensor_{i}, {i}"
}
let fileName = $"{dummyRecords.GetHashCode()}.csv"
File.WriteAllLines(fileName, dummyRecords)
let createSql = "create table test_table(col1 text, col2 integer);"
let! conn = env.Database.OpenConnection()
conn.Execute(createSql) |> ignore
let insertSql = $"copy test_table from '{fileName}' (auto_detect true);"
conn.Execute(insertSql) |> ignore
File.Delete(fileName)
}
type DbReturn<'t> = {query_value: 't}
let selectMin (env: #IDb) = async{
use! conn = env.Database.OpenConnection()
let x = conn.Query<DbReturn<int>>("select min(col2) query_value from test_table") |> Seq.exactlyOne
return x.query_value
}
let selectMax (env: #IDb) = async{
use! conn = env.Database.OpenConnection()
let x = conn.Query<DbReturn<int>>("select max(col2) query_value from test_table") |> Seq.exactlyOne
return x.query_value
}
let selectAvg (env: #IDb) = async{
use! conn = env.Database.OpenConnection()
let x = conn.Query<DbReturn<float>>("select avg(col2) query_value from test_table") |> Seq.exactlyOne
return x.query_value |> int
}
let getSum1 env = async{
//sequentially run the queries
let! minVal = selectMin env
let! maxVal = selectMax env
let! avgVal = selectAvg env
return minVal + maxVal + avgVal
}
let getSum2 env = async{
//concurrently run the queries
let! minVal = selectMin env
and! maxVal = selectMax env
and! avgVal = selectAvg env
return minVal + maxVal + avgVal
}
let test1 env = testAsync "Sequential Connection Sequential Query" {
let! sum = getSum1 env
sum |> Expect.equal "" 150001
}
let test2 (env: #IDb) = testAsync "Sequential Connection Concurrent Query" {
let! sum = getSum2 env
sum |> Expect.equal "" 150001
}
let test3 (env: #IDb) = testAsync "Sequential Connection Concurrent Query2" {
let! sum = getSum2 env
sum |> Expect.equal "" 150001
}
let allTests env =
testList ""
[
//test1 env
//test2 env
test3 env
]
[<EntryPoint>]
let main argv =
let dbName = "test.db"
if File.Exists(dbName) then
File.Delete(dbName)
//implement the database dependency interface
let database = {
new IDatabase with
member this.OpenConnection() = async{
return new DuckDBConnection($"Data Source={dbName}")
}
}
let env = {
new IDb with
member this.Database = database
}
initialiseDb env |> Async.RunSynchronously
runTestsWithCLIArgs [] argv (allTests env)