From 38e6717f76111f1ce294202317066358ac2cbed8 Mon Sep 17 00:00:00 2001
From: Matei Adriel <rafaeladriel11@gmail.com>
Date: Thu, 2 Jan 2020 15:37:47 +0200
Subject: [PATCH] fsharp(todolist-api): feat: editing todos

Signed-off-by: prescientmoon <git@moonythm.dev>
---
 fsharp/todolist-api/src/App.fs | 55 +++++++++++++++++++++++++++++-----
 fsharp/todolist-api/src/Db.fs  | 22 +++++++++-----
 2 files changed, 63 insertions(+), 14 deletions(-)

diff --git a/fsharp/todolist-api/src/App.fs b/fsharp/todolist-api/src/App.fs
index adc665e..a4eede5 100644
--- a/fsharp/todolist-api/src/App.fs
+++ b/fsharp/todolist-api/src/App.fs
@@ -1,34 +1,75 @@
 // Learn more about F# at http://fsharp.org
+open System
 
+// suave overwrites some stuff from f#+, so the order matters
+open FSharpPlus.Operators
 open Suave
-open Suave.Successful
 open Suave.Operators
-open Suave.Filters
+open Suave.Successful
 open Suave.RequestErrors
 open Suave.Json
+open Suave.Filters
 
 module Utils = 
     open System.Text
+    open Db.Types
 
     let jsonToString json = json |> toJson |> Encoding.UTF8.GetString
 
+    let todoToRecord (todo: DbTodo) =
+        { id = todo.Id
+          description = todo.Description
+          name = todo.Name }
+
 module App =
     open Utils
+    open Db
 
     let todoById (id) = 
-        let todo = Db.Context.getContext() |> Db.Queries.getTodosById id
+        let todo = 
+            Context.getContext() 
+            |> Queries.getTodosById id 
+            |>> todoToRecord
 
         match todo with 
         | Some inner -> inner |> jsonToString |>  OK
         | None -> id |> sprintf "Cannot find todo with id %i" |> NOT_FOUND 
 
+    let updateTodo (id) =
+        let dbContext = Context.getContext()
+        let todo = dbContext |> Queries.getTodosById id
+
+        match todo with 
+        | Some todo -> 
+            fun ctx -> async {
+                    let body: Types.TodoDetails = ctx.request.rawForm |> fromJson
+
+                    do! Queries.updateTodosById todo body dbContext
+
+                    let newBody: Types.Todo = {
+                        name = body.name
+                        description = body.description
+                        id = id
+                    } 
+
+                    let withNewBody = newBody |> toJson |> ok
+                    return! withNewBody ctx
+                }
+                
+        | None -> id |> sprintf "Cannot find todo with id %i" |> NOT_FOUND 
+
+
     let mainWebPart: WebPart = choose [
-        GET >=> choose [
-            pathScan "/todos/%i" todoById
-        ]]
+        GET >=> pathScan "/todos/%i" todoById
+        PUT >=> pathScan "/todos/%i" updateTodo]
 
 [<EntryPoint>]
 let main _ =
-    startWebServer defaultConfig App.mainWebPart
+
+    let handleErrors (e: Exception) (message: string): WebPart = 
+        sprintf "%s: %s" message e.Message |> BAD_REQUEST  
+    let config = { defaultConfig with errorHandler = handleErrors }
+
+    startWebServer config App.mainWebPart
 
     0 // return an integer exit code
diff --git a/fsharp/todolist-api/src/Db.fs b/fsharp/todolist-api/src/Db.fs
index 0f13d4e..a57faee 100644
--- a/fsharp/todolist-api/src/Db.fs
+++ b/fsharp/todolist-api/src/Db.fs
@@ -30,23 +30,31 @@ module Types =
           name: string }
 
 
-    let todoToRecord (todo: DbTodo) =
-        { id = todo.Id
-          description = todo.Description
-          name = todo.Name }
+    [<DataContract>]
+    type TodoDetails =
+        { [<field:DataMember(Name = "description")>]
+          description: string
+          [<field:DataMember(Name = "name")>]
+          name: string }
+
 
 
 module Queries =
-    open FSharpPlus.Operators
     open Context
     open Types
 
-    let getTodosById id (ctx: DbContext): Todo option =
+    let getTodosById id (ctx: DbContext): DbTodo option =
         query {
             for todo in ctx.Public.Todos do
                 where (todo.Id = id)
                 select todo
         }
         |> Seq.tryHead
-        |>> todoToRecord
+
+
+    let updateTodosById (todo: DbTodo) (details: TodoDetails) (ctx: DbContext) =
+        todo.Name <- details.name
+        todo.Description <- details.description
+
+        ctx.SubmitUpdatesAsync()
  
\ No newline at end of file