module Degenz.DbService open Degenz.Types open System open MongoDB.Bson open MongoDB.Bson.Serialization open MongoDB.Driver let mongo = MongoClient(Environment.GetEnvironmentVariable("CONN_STRING")) let db = mongo.GetDatabase("degenz") let players = db.GetCollection("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 (bson : BsonDocument) : PlayerData = { DiscordId = tryWithDefault bson "DiscordId" 0uL (fun v -> v.AsInt64 |> uint64) Name = tryWithDefault bson "Name" "Empty" (fun v -> v.AsString) Inventory = tryWithDefault bson "Inventory" [||] (fun v -> v.AsBsonArray |> Seq.map (fun (bv : BsonValue) -> BsonSerializer.Deserialize(bv.ToBsonDocument())) |> Seq.toArray) Events = tryWithDefault bson "Events" [||] (fun v -> v.AsBsonArray |> Seq.map (fun (bv : BsonValue) -> BsonSerializer.Deserialize(bv.ToBsonDocument())) |> Seq.toArray) Traits = tryWithDefault bson "Traits" PlayerTraits.empty (fun v -> BsonSerializer.Deserialize(v.ToBsonDocument())) 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 = tryWithDefault bson "Bank" 0 (fun v -> v.AsInt32 * 1) } let tryFindPlayer (id : uint64) = async { let filter = Builders.Filter.Eq("Player.DiscordId", id) let! player = players.FindAsync(filter) |> Async.AwaitTask match player.FirstOrDefault() with | null -> return None | p -> let v = p.GetValue("Player") let playerData = v.ToBsonDocument() |> mapBack 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.Filter.Eq("Player.DiscordId", player.DiscordId) let update = Builders.Update.Set("Player", player.ToBsonDocument()) do! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore } let addAchievement (id : uint64) (achievement : string) = async { let filter = Builders.Filter.Eq("Player.DiscordId", id) let update = Builders.Update.Push("Player.Achievements", achievement) return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore }