99 lines
3.3 KiB
Forth
99 lines
3.3 KiB
Forth
module JobsJobsJobs.Api.Data
|
|
|
|
open JobsJobsJobs.Api.Domain
|
|
open Npgsql.FSharp
|
|
open System
|
|
|
|
/// The connection URI for the database
|
|
let connectUri = Uri config.dbUri
|
|
|
|
|
|
/// Connect to the database
|
|
let db () =
|
|
(Sql.fromUri >> Sql.connect) connectUri
|
|
|
|
|
|
/// Return None if the error is that a single row was expected, but no rows matched
|
|
let private noneIfNotFound (it : Async<Result<'T, exn>>) = async {
|
|
match! it with
|
|
| Ok x ->
|
|
return (Some >> Ok) x
|
|
| Error err ->
|
|
return match err.Message with msg when msg.Contains "at least one" -> Ok None | _ -> Error err
|
|
}
|
|
|
|
|
|
/// Get the item count from a single-row result
|
|
let private itemCount (read: RowReader) = read.int64 "item_count"
|
|
|
|
|
|
/// Functions for manipulating citizens
|
|
// (SHUT UP, SLAVE!)
|
|
module Citizens =
|
|
|
|
/// Create a Citizen from a row of data
|
|
let private fromReader (read: RowReader) =
|
|
match (read.string >> CitizenId.tryParse) "id" with
|
|
| Ok citizenId -> {
|
|
id = citizenId
|
|
naUser = read.string "na_user"
|
|
displayName = read.string "display_name"
|
|
profileUrl = read.string "profile_url"
|
|
joinedOn = (read.int64 >> Millis) "joined_on"
|
|
lastSeenOn = (read.int64 >> Millis) "last_seen_on"
|
|
}
|
|
| Error err -> failwith err
|
|
|
|
/// Determine if we already know about this user from No Agenda Social
|
|
let findIdByNaUser naUser =
|
|
db ()
|
|
|> Sql.query "SELECT id FROM citizen WHERE na_user = @na_user"
|
|
|> Sql.parameters [ "@na_user", Sql.string naUser ]
|
|
|> Sql.executeRowAsync (fun read ->
|
|
match (read.string >> CitizenId.tryParse) "id" with
|
|
| Ok citizenId -> citizenId
|
|
| Error err -> failwith err)
|
|
|> noneIfNotFound
|
|
|
|
/// Add a citizen
|
|
let add citizen =
|
|
db ()
|
|
|> Sql.query
|
|
"""INSERT INTO citizen (
|
|
na_user, display_name, profile_url, joined_on, last_seen_on, id
|
|
) VALUES (
|
|
@na_user, @display_name, @profile_url, @joined_on, @last_seen_on, @id
|
|
)"""
|
|
|> Sql.parameters [
|
|
"@na_user", Sql.string citizen.naUser
|
|
"@display_name", Sql.string citizen.displayName
|
|
"@profile_url", Sql.string citizen.profileUrl
|
|
"@joined_on", (Millis.toLong >> Sql.int64) citizen.joinedOn
|
|
"@last_seen_on", (Millis.toLong >> Sql.int64) citizen.lastSeenOn
|
|
"@id", (CitizenId.toString >> Sql.string) citizen.id
|
|
]
|
|
|> Sql.executeNonQueryAsync
|
|
|
|
/// Update a citizen record when they log on
|
|
let update citizenId displayName =
|
|
db ()
|
|
|> Sql.query
|
|
"""UPDATE citizen
|
|
SET display_name = @display_name,
|
|
last_seen_on = @last_seen_on
|
|
WHERE id = @id"""
|
|
|> Sql.parameters [
|
|
"@display_name", Sql.string displayName
|
|
"@last_seen_on", (DateTime.Now.toMillis >> Millis.toLong >> Sql.int64) ()
|
|
"@id", (CitizenId.toString >> Sql.string) citizenId
|
|
]
|
|
|> Sql.executeNonQueryAsync
|
|
|
|
/// Try to find a citizen with the given ID
|
|
let tryFind citizenId =
|
|
db ()
|
|
|> Sql.query "SELECT * FROM citizen WHERE id = @id"
|
|
|> Sql.parameters [ "@id", (CitizenId.toString >> Sql.string) citizenId ]
|
|
|> Sql.executeRowAsync fromReader
|
|
|> noneIfNotFound
|