From f3a4b3c957e2ce2741e84aec77fc611373f27421 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Thu, 2 Jan 2020 17:24:57 +0200 Subject: [PATCH] fsharp(todolist-api): feat: got patching to work Signed-off-by: prescientmoon --- 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 + ])] [] 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