99 lines
3.5 KiB
Forth

module Degenz.DbService
open Degenz.Types
open System
open MongoDB.Bson
open MongoDB.Bson.Serialization
open MongoDB.Driver
open Npgsql.FSharp
type User = {
Name : string
DiscordId : uint64
Bank : int<GBT>
Strength : int
Inventory : int array
}
let mongo = MongoClient(Environment.GetEnvironmentVariable("CONN_STRING"))
let db = mongo.GetDatabase("degenz")
let players = db.GetCollection<BsonDocument>("players")
let tryWithDefault (bson : BsonDocument) field (defaultValue : 'a) (map : BsonValue -> 'a) =
try
let result , bval = bson.TryGetValue(field)
if result then map bval else defaultValue
with _ -> defaultValue
let mapBack user (bson : BsonDocument) : PlayerData =
{ DiscordId = user.DiscordId
Name = user.Name
Inventory =
user.Inventory
|> Array.map (fun iId ->
Armory.battleItems
|> Array.tryFind (fun i -> i.Id = iId)
|> function
| Some i -> [| i |]
| None -> [||])
|> Array.concat
Events = tryWithDefault bson "Events" [||] (fun v ->
v.AsBsonArray
|> Seq.map (fun (bv : BsonValue) ->
BsonSerializer.Deserialize<PlayerEvent>(bv.ToBsonDocument()))
|> Seq.toArray)
Traits = { PlayerTraits.empty with Strength = user.Strength }
// Achievements =
// tryWithDefault bson "Achievements" [||] (fun v ->
// v.AsBsonArray |> Seq.map (fun (bv : BsonValue) -> bv.AsString) |> Seq.toArray)
// XP = tryWithDefault bson "XP" 0 (fun v -> v.AsInt32)
Bank = user.Bank
}
let tryFindPlayer connStr (id : uint64) =
async {
let filter = Builders<BsonDocument>.Filter.Eq("Player.DiscordId", id)
let! player = players.FindAsync<BsonDocument>(filter) |> Async.AwaitTask
let! user =
connStr
|> Sql.connect
|> Sql.query "SELECT * FROM users WHERE discordId = @did"
|> Sql.parameters [ "did", Sql.int64 (int64 id) ]
|> Sql.executeAsync (fun read ->
{
DiscordId = read.int64 "discordId" |> uint64
Name = read.string "displayName"
Bank = read.int "gbt" * 1<GBT>
Strength = read.int "strength"
Inventory = read.intArray "inventory"
})
|> Async.AwaitTask
match player.FirstOrDefault() , List.tryHead user with
| null , _
| _ , None -> return None
| p , Some u ->
let v = p.GetValue("Player")
let playerData = mapBack u (v.ToBsonDocument())
return Some playerData
}
let insertNewPlayer (player : PlayerData) =
async {
do! BsonDocument("Player", player.ToBsonDocument()) |> players.InsertOneAsync |> Async.AwaitTask
}
let updatePlayer (player : PlayerData) =
async {
let filter = Builders<BsonDocument>.Filter.Eq("Player.DiscordId", player.DiscordId)
let update = Builders<BsonDocument>.Update.Set("Player", player.ToBsonDocument())
do! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
}
let addAchievement (id : uint64) (achievement : string) =
async {
let filter = Builders<BsonDocument>.Filter.Eq("Player.DiscordId", id)
let update = Builders<BsonDocument>.Update.Push("Player.Achievements", achievement)
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
}