From f3a4b3c957e2ce2741e84aec77fc611373f27421 Mon Sep 17 00:00:00 2001
From: Matei Adriel <rafaeladriel11@gmail.com>
Date: Thu, 2 Jan 2020 17:24:57 +0200
Subject: [PATCH] fsharp(todolist-api): feat: got patching to work

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

diff --git a/fsharp/todolist-api/src/App.fs b/fsharp/todolist-api/src/App.fs
index 178b388..5584734 100644
--- a/fsharp/todolist-api/src/App.fs
+++ b/fsharp/todolist-api/src/App.fs
@@ -1,8 +1,6 @@
 // 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.Operators
 open Suave.Successful
@@ -19,7 +17,7 @@ module Utils =
           description = todo.Description
           name = todo.Name }
           
-    let parseJson (input: byte array) = input |> Encoding.UTF8.GetString |> Json.parse |> Json.deserialize
+    let inline parseJson (input: byte array) = input |> Encoding.UTF8.GetString |> Json.parse |> Json.deserialize
 
 module App =
     open Utils
@@ -39,25 +37,46 @@ module App =
     let updateTodo =
         withTodoById (fun (todo, dbContext, id) ->
             fun ctx -> async {
-                    let body: Types.TodoDetails = parseJson ctx.request.rawForm
+                let body: Types.TodoDetails = parseJson ctx.request.rawForm
 
-                    do! Queries.updateTodosById todo body dbContext
+                do! Queries.updateTodoById todo body dbContext
 
-                    let newBody: Types.Todo = {
-                        name = body.name
-                        description = body.description
-                        id = id
-                    } 
+                let newBody: Types.Todo = {
+                    name = body.name
+                    description = body.description
+                    id = id
+                } 
 
-                    let writeBody = newBody |> Json.serialize |> Json.format |> OK
+                let writeBody = newBody |> Json.serialize |> Json.format |> OK
 
-                    return! writeBody ctx 
-                }        
-        ) 
+                return! writeBody ctx 
+            }) 
+
+    let patchTodo = withTodoById (fun (todo, dbContext, id) ->
+            let originalTodo = todoToRecord todo
+            
+            fun ctx -> async {
+                let body: Types.PartialTodoDetails = parseJson ctx.request.rawForm
+
+                do! Queries.patchTodoById todo body dbContext
+
+                let newBody: Types.Todo = {
+                    name = Option.defaultValue originalTodo.name body.name
+                    description = Option.defaultValue originalTodo.description body.description
+                    id = id
+                } 
+
+                let writeBody = newBody |> Json.serialize |> Json.format |> OK
+
+                return! writeBody ctx 
+            })
 
     let mainWebPart: WebPart = choose [
-        GET >=> pathScan "/todos/%i" todoById
-        PUT >=> pathScan "/todos/%i" updateTodo]
+         pathScan "/todos/%i" (fun (id) -> choose [
+            GET >=>  todoById id
+            PUT >=>  updateTodo id
+            PATCH >=> patchTodo id
+            ])]
 
 [<EntryPoint>]
 let main _ =
diff --git a/fsharp/todolist-api/src/Db.fs b/fsharp/todolist-api/src/Db.fs
index 26ed0d5..e541aa7 100644
--- a/fsharp/todolist-api/src/Db.fs
+++ b/fsharp/todolist-api/src/Db.fs
@@ -54,9 +54,20 @@ module Types =
                          description = description }
             }
 
+    type PartialTodoDetails =
+        { description: string option
+          name: string option }
+        static member FromJson(_: PartialTodoDetails) =
+            json {
+                let! name = Json.tryRead "name"
+                let! description = Json.tryRead "description"
+                return { name = name
+                         description = description }
+            }
 
 
 module Queries =
+    open FSharpPlus.Builders
     open Context
     open Types
 
@@ -69,9 +80,17 @@ module Queries =
         |> Seq.tryHead
 
 
-    let updateTodosById (todo: DbTodo) (details: TodoDetails) (ctx: DbContext) =
+    let updateTodoById (todo: DbTodo) (details: TodoDetails) (ctx: DbContext) =
         todo.Name <- details.name
         todo.Description <- details.description
 
         ctx.SubmitUpdatesAsync()
+
+    let patchTodoById (todo: DbTodo) (details: PartialTodoDetails) (ctx: DbContext) =
+        Option.iter (fun name -> todo.Name <- name) details.name
+        Option.iter (fun description -> todo.Description <- description) details.description
+
+        if Option.orElse details.name details.description |> Option.isSome
+        then ctx.SubmitUpdatesAsync()
+        else Async.result()
  
\ No newline at end of file