-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Fsharp giraffe fortunes #3863
Fsharp giraffe fortunes #3863
Changes from 30 commits
949ed89
3e0c166
3c6d0b7
e3f19f6
9cebdac
51fa142
5e99be4
9b0b536
3d3823a
626ebfa
4840227
b8fad79
db2817a
f7189e3
8cd915f
8243388
74ae1d7
7a71975
c517b24
e8b610b
cbacce8
ff5cb17
7e08d65
6769441
d2f92a3
a7cc240
11d00e1
0265682
5826708
78b1ebe
a8ea10b
7584295
0bb0e5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,19 +5,20 @@ | |
"default": { | ||
"plaintext_url": "/plaintext", | ||
"json_url": "/json", | ||
"fortune_url": "/fortunes", | ||
"port": 8080, | ||
"approach": "Realistic", | ||
"classification": "fullstack", | ||
"database": "None", | ||
"database": "Postgres", | ||
"framework": "giraffe", | ||
"language": "F#", | ||
"orm": "Raw", | ||
"orm": "micro", | ||
"platform": ".NET", | ||
"flavor": "CoreCLR", | ||
"webserver": "Kestrel", | ||
"os": "Linux", | ||
"database_os": "Linux", | ||
"display_name": "Giraffe", | ||
"display_name": "Giraffe, Dapper", | ||
"notes": "", | ||
"versus": "aspcore" | ||
} | ||
|
@@ -27,7 +28,7 @@ | |
"json_url": "/json", | ||
"port": 8080, | ||
"approach": "Realistic", | ||
"classification": "fullstack", | ||
"classification": "Micro", | ||
"database": "None", | ||
"framework": "giraffe", | ||
"language": "F#", | ||
|
@@ -37,27 +38,28 @@ | |
"webserver": "Kestrel", | ||
"os": "Linux", | ||
"database_os": "Linux", | ||
"display_name": "Giraffe", | ||
"display_name": "Giraffe, utf8json", | ||
"notes": "", | ||
"versus": "aspcore" | ||
} | ||
}, | ||
{ | ||
"utf8plaintext": { | ||
"stripped": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"fortune_url": "/fortunes", | ||
"plaintext_url": "/plaintext", | ||
"port": 8080, | ||
"approach": "Realistic", | ||
"classification": "fullstack", | ||
"database": "None", | ||
"approach": "Stripped", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its still There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In recent run its 1,347,868.6 rps vs 1,220,305.2 rps for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also |
||
"classification": "Micro", | ||
"database": "Postgres", | ||
"framework": "giraffe", | ||
"language": "F#", | ||
"orm": "Raw", | ||
"orm": "micro", | ||
"platform": ".NET", | ||
"flavor": "CoreCLR", | ||
"webserver": "Kestrel", | ||
"os": "Linux", | ||
"database_os": "Linux", | ||
"display_name": "Giraffe", | ||
"display_name": "Giraffe, Custom Rendering, Dapper", | ||
"notes": "", | ||
"versus": "aspcore" | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
module Custom | ||
|
||
open App | ||
open Dapper | ||
open Giraffe | ||
open System | ||
open Models | ||
open Npgsql | ||
open FSharp.Control.Tasks | ||
|
||
let application : HttpHandler = | ||
|
||
let inline contentLength x = new Nullable<int64> ( int64 x ) | ||
|
||
let json' data : HttpHandler = | ||
let bytes = Utf8Json.JsonSerializer.Serialize(data) | ||
fun _ ctx -> | ||
ctx.Response.ContentLength <- contentLength bytes.Length | ||
ctx.Response.ContentType <- "application/json" | ||
ctx.Response.StatusCode <- 200 | ||
task { | ||
do! ctx.Response.Body.WriteAsync(bytes, 0, bytes.Length) | ||
return Some ctx | ||
} | ||
|
||
let text' (msg:string): HttpHandler = | ||
let bytes = System.Text.Encoding.UTF8.GetBytes(msg) | ||
fun _ ctx -> | ||
ctx.Response.ContentLength <- contentLength bytes.Length | ||
ctx.Response.ContentType <- "text/plain" | ||
ctx.Response.StatusCode <- 200 | ||
task { | ||
do! ctx.Response.Body.WriteAsync(bytes, 0, bytes.Length) | ||
return Some ctx | ||
} | ||
|
||
let fortunes' : HttpHandler = | ||
let extra = { id = 0; message = "Additional fortune added at request time." } | ||
fun _ ctx -> | ||
|
||
let conn = new NpgsqlConnection(ConnectionString) | ||
ctx.Response.RegisterForDispose conn | ||
|
||
task { | ||
let! data = conn.QueryAsync<Fortune>("SELECT id, message FROM fortune") | ||
|
||
let fortunes = | ||
let xs = data.AsList() | ||
xs.Add extra | ||
xs.Sort FortuneComparer | ||
xs | ||
|
||
let html = fortunes |> HtmlViews.fortunes |> StetefullRendering.renderHtml | ||
|
||
ctx.Response.ContentType <- "text/html;charset=utf-8" | ||
ctx.Response.ContentLength <- contentLength html.Length | ||
ctx.Response.StatusCode <- 200 | ||
do! html.CopyToAsync ctx.Response.Body | ||
return Some ctx | ||
} | ||
|
||
let routes' (routes: (string * HttpHandler) list) : HttpHandler = | ||
let table = Map.ofList routes | ||
let notFound = setStatusCode 404 | ||
|
||
let go key = | ||
if table |> Map.containsKey key then | ||
table.[key] | ||
else | ||
notFound | ||
|
||
fun next ctx -> | ||
let path = ctx.Request.Path.Value | ||
let handler = go path | ||
handler next ctx | ||
|
||
routes' [ | ||
"/plaintext", text' "Hello, World!" | ||
"/json", json' { JsonStructMessage.message = "Hello, World!" } | ||
"/fortunes", fortunes' | ||
] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
module HtmlViews | ||
|
||
open Giraffe.GiraffeViewEngine | ||
open Models | ||
|
||
let private fortunesHead = | ||
head [] [ | ||
title [] [ rawText "Fortunes" ] | ||
] | ||
|
||
let private layout (content: XmlNode list) = | ||
html [] [ | ||
fortunesHead | ||
body [] content | ||
] | ||
|
||
let private fortunesTableHeader = | ||
tr [] [ | ||
th [] [ rawText "id" ] | ||
th [] [ rawText "message" ] | ||
] | ||
|
||
let fortunes (fortunes: Fortune seq) = | ||
[ | ||
table [] [ | ||
yield fortunesTableHeader | ||
for f in fortunes -> | ||
tr [] [ | ||
td [] [ rawText <| string f.id ] | ||
td [] [ encodedText <| f.message ] | ||
] | ||
] | ||
] |> layout |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
module Models | ||
|
||
open System.Collections.Generic | ||
open System | ||
|
||
type JsonMessage = { message : string } | ||
|
||
[<Struct>] | ||
type JsonStructMessage = { message : string } | ||
|
||
[<CLIMutable>] | ||
type Fortune = { id: int; message: string } | ||
|
||
[<Literal>] | ||
let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3" | ||
|
||
type Implementation = Stock | Custom | ||
|
||
let FortuneComparer = { new IComparer<Fortune> with | ||
member self.Compare(a,b) = String.CompareOrdinal(a.message, b.message) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big fan of this, but since we don't have a key for the name of your database approach/library, I guess it will do.