summaryrefslogtreecommitdiff
path: root/lib/handler.ml
blob: c1ba53d37fb759aad74c1c538794e281beb87f69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
open Piaf

type pool = ((module Rapper_helper.CONNECTION), Caqti_error.t) Caqti_eio.Pool.t

let create_transaction client_id (db_pool : pool) (request : Request.t) =
  Caqti_eio.Pool.use
    (fun conn ->
      let module C = (val conn : Rapper_helper.CONNECTION) in
      C.with_transaction
      @@ fun () ->
      ignore @@ Query.lock client_id conn;
      let client_opt =
        Option.join @@ Result.to_option @@ Query.find_client client_id conn
      in
      match client_opt with
      | Some client ->
        let body = Result.to_option @@ Body.to_string request.body in
        let json =
          Option.map
            (fun str ->
              try Yojson.Safe.from_string str with
              | _ -> `Null)
            body
        in
        let decoded_op = Option.bind json (Utils.Decoder.decode Operation.decoder) in
        let insert_result =
          match decoded_op with
          | Some (`Credit { value = _value; description = _desc } as op) ->
            (match Query.execute_transaction ~client_id ~op conn with
             | Ok _ as ok -> ok
             | Error e -> Error (`DB e))
          | Some (`Debit { value; description = _desc } as op) ->
            let valid_debit =
              let balance_after_op = client.balance - value in
              not (balance_after_op < client.mov_limit * -1)
            in
            if valid_debit
            then (
              match Query.execute_transaction ~client_id ~op conn with
              | Ok _ as ok -> ok
              | Error e -> Error (`DB e))
            else Error `InvalidValue
          | None -> Error (`Decoder "Invalid operation")
        in
        (match insert_result with
         | Ok () ->
           let client =
             Option.get
             @@ Option.join
             @@ Result.to_option
             @@ Query.find_client client_id conn
           in
           let json : Yojson.Safe.t =
             `Assoc [ "limite", `Int client.mov_limit; "saldo", `Int client.balance ]
           in
           Ok (Response.of_string ~body:(Yojson.Safe.to_string json) `OK)
         | Error _ -> Ok (Response.create (`Code 422)))
      | None ->
        Logs.info (fun m -> m "Não encontrei o cliente %d" client_id);
        Ok (Response.create `Not_found))
    db_pool
;;

let get_balance client_id (db_pool : pool) (_request : Request.t) =
  Caqti_eio.Pool.use
    (fun conn ->
      let client_opt =
        Option.join @@ Result.to_option @@ Query.find_client client_id conn
      in
      match client_opt with
      | Some client ->
        let transaction_list =
          (* NOTE: Talvez isso aqui não seja uma boa ideia *)
          Result.fold ~ok:Fun.id ~error:(fun _ -> []) @@ Query.transactions client_id conn
        in
        let json =
          let time = Option.get @@ Ptime.of_float_s (Unix.time ()) in
          Serializer.bank_statement time client transaction_list
        in
        Ok (Response.of_string ~body:(Yojson.Safe.to_string json) `OK)
      | None ->
        Logs.info (fun m -> m "Não encontrei o cliente %d" client_id);
        Ok (Response.create `Not_found))
    db_pool
;;