summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateus Cruz <mateuscolvr@gmail.com>2024-02-05 11:06:46 -0300
committerMateus Cruz <mateuscolvr@gmail.com>2024-02-05 11:06:46 -0300
commit8878b1d92bdd8ee9b51ecde7e9cc88f62f264841 (patch)
tree46d6c47dfc820689baa552d97255adeda4c98b15
parent5a2f5bf9a12b270e15757df48afeb1c1db5b34b3 (diff)
move routes handler module to its own file
-rw-r--r--bin/main.ml8
-rw-r--r--docker-compose.yml4
-rw-r--r--lib/handler.ml63
-rw-r--r--lib/query.ml76
-rw-r--r--lib/router.ml49
-rw-r--r--script.sql4
6 files changed, 120 insertions, 84 deletions
diff --git a/bin/main.ml b/bin/main.ml
index 99cc0e0..3f11200 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -1,12 +1,9 @@
-[@@@warning "-26-27-32"]
-
-open! StdLabels
open Eio
open Piaf
let request_handler ~db_pool Server.{ request; _ } =
match Rinha.Router.match_route request.meth request.target with
- | Some handler -> handler db_pool request
+ | Some handler -> Result.get_ok @@ handler db_pool request
| None -> Response.create `Not_found
;;
@@ -25,7 +22,8 @@ let () =
Uri.make ~scheme:"postgres" ~userinfo:"admin:123" ~host:"db" ~path:"rinha" ()
in
let db_pool =
- Result.get_ok @@ Caqti_eio.connect_pool ~sw ~stdenv:(env :> Caqti_eio.stdenv) db_uri
+ Result.get_ok
+ @@ Caqti_eio_unix.connect_pool ~sw ~stdenv:(env :> Caqti_eio.stdenv) db_uri
in
let server = Server.create ~config (request_handler ~db_pool) in
ignore @@ Server.Command.start ~sw env server
diff --git a/docker-compose.yml b/docker-compose.yml
index 03ed942..9c58e3f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -5,8 +5,6 @@ services:
image: rinha:latest
environment:
- DB_HOST=db
- ports:
- - 8081:8080
depends_on:
- db
deploy:
@@ -19,8 +17,6 @@ services:
<<: *api
environment:
- DB_HOST=db
- ports:
- - 8082:8080
nginx:
image: nginx:latest
diff --git a/lib/handler.ml b/lib/handler.ml
new file mode 100644
index 0000000..4ee7189
--- /dev/null
+++ b/lib/handler.ml
@@ -0,0 +1,63 @@
+open Piaf
+
+let create_transaction client_id (db_pool : Query.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 insert_result =
+ let body = Result.to_option @@ Body.to_string request.body in
+ let json = Option.map Yojson.Safe.from_string body in
+ let decoded_op = Option.bind json (Utils.Decoder.decode Operation.decoder) in
+ match decoded_op with
+ | Some op ->
+ (match Query.execute_operation ~client_id ~op conn with
+ | Ok _ as ok -> ok
+ | Error e -> Error (`DB e))
+ | None -> Error (`Decoder "Invalid operation")
+ in
+ (match insert_result with
+ | Ok () ->
+ let json : Yojson.Safe.t =
+ `Assoc [ "limite", `Int 100000; "saldo", `Int (-9098) ]
+ in
+ Ok (Response.of_string ~body:(Yojson.Safe.to_string json) `OK)
+ | Error _ -> Ok (Response.create (`Code 422)))
+ | None -> Ok (Response.create `Not_found))
+ db_pool
+;;
+
+let get_balance client_id (db_pool : Query.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 client_balance_opt =
+ Option.join @@ Result.to_option @@ Query.balance client_id conn
+ in
+ (match client_balance_opt with
+ | Some (balance_value, time) ->
+ let json : Yojson.Safe.t =
+ let balance =
+ let total = `Int balance_value in
+ let date =
+ `String
+ (Format.asprintf "%a" (Ptime.pp_rfc3339 ~tz_offset_s:(-10800) ()) time)
+ in
+ let limit = `Int 100000 in
+ `Assoc [ "total", total; "data_extrato", date; "limite", limit ]
+ in
+ let last_transactions = `List [] in
+ `Assoc [ "saldo", balance; "ultimas_transacoes", last_transactions ]
+ in
+ Ok (Response.of_string ~body:(Yojson.Safe.to_string json) `OK)
+ | None -> Ok (Response.create `Not_found))
+ | None -> Ok (Response.create `Not_found))
+ db_pool
+;;
diff --git a/lib/query.ml b/lib/query.ml
index 0fb6f7e..85f91f0 100644
--- a/lib/query.ml
+++ b/lib/query.ml
@@ -1,37 +1,61 @@
type pool = ((module Rapper_helper.CONNECTION), Caqti_error.t) Caqti_eio.Pool.t
-let transaction_query =
- [%rapper
- execute
- {sql|
+module Q = struct
+ let transaction =
+ [%rapper
+ execute
+ {sql|
INSERT INTO transactions (client_id, value, type, description)
VALUES (%int{client_id}, %int{value}, %Operation.TransactionType{transaction_type}, %string{description})
|sql}]
-;;
+ ;;
-let client_query =
- let open Client in
- [%rapper
- get_opt
- {sql|
- SELECT @int{id}, @int{mov_limit} FROM clients WHERE id = %int{id}
- |sql}
- record_out]
-;;
+ let debit =
+ [%rapper
+ execute
+ {sql|
+ UPDATE balances SET value = value - %int{value} WHERE client_id = %int{client_id}
+ |sql}]
+ ;;
+
+ let credit =
+ [%rapper
+ execute
+ {sql|
+ UPDATE balances SET value = value + %int{value} WHERE client_id = %int{client_id}
+ |sql}]
+ ;;
+
+ let client =
+ let open Client in
+ [%rapper
+ get_opt
+ {sql|
+ SELECT @int{id}, @int{mov_limit} FROM clients WHERE id = %int{id}
+ |sql}
+ record_out]
+ ;;
+
+ let balance =
+ [%rapper
+ get_opt
+ {sql|
+ SELECT @int{value}, @ptime{now()} as time FROM balances WHERE client_id = %int{client_id}
+ |sql}]
+ ;;
+end
+
+let ( let* ) = Result.bind
-let execute_operation ~client_id ~(op : Operation.t) pool =
+let execute_operation ~client_id ~(op : Operation.t) conn =
match op with
- | Transaction data ->
- Caqti_eio.Pool.use
- (fun conn ->
- transaction_query
- ~client_id
- ~value:data.value
- ~transaction_type:data.transaction_type
- ~description:data.description
- conn)
- pool
+ | Transaction { value; description; transaction_type } ->
+ let* () = Q.transaction ~client_id ~value ~description conn ~transaction_type in
+ (match transaction_type with
+ | Credit -> Q.credit ~value ~client_id conn
+ | Debit -> Q.debit ~value ~client_id conn)
| _ -> failwith "TODO"
;;
-let find_client id pool = Caqti_eio.Pool.use (fun conn -> client_query ~id conn) pool
+let find_client id conn = Q.client ~id conn
+let balance client_id conn = Q.balance ~client_id conn
diff --git a/lib/router.ml b/lib/router.ml
index 35cef34..4572978 100644
--- a/lib/router.ml
+++ b/lib/router.ml
@@ -1,5 +1,3 @@
-[@@@warning "-26-27-32"]
-
open StdLabels
open Routes
open Piaf
@@ -14,55 +12,12 @@ module R = Map.Make (struct
;;
end)
-module Handler = struct
- let transaction client_id (db_pool : Query.pool) (request : Request.t) =
- let client_opt =
- Option.join @@ Result.to_option @@ Query.find_client client_id db_pool
- in
- match client_opt with
- | Some client ->
- let insert_result =
- let body = Result.to_option @@ Body.to_string request.body in
- let json = Option.map Yojson.Safe.from_string body in
- let decoded_op = Option.bind json (Utils.Decoder.decode Operation.decoder) in
- match decoded_op with
- | Some op ->
- (match Query.execute_operation ~client_id ~op db_pool with
- | Ok _ as ok -> ok
- | Error e -> Error (`DB e))
- | None -> Error (`Decoder "Invalid operation")
- in
- (match insert_result with
- | Ok () ->
- let json : Yojson.Safe.t =
- `Assoc [ "limite", `Int 100000; "saldo", `Int (-9098) ]
- in
- Response.of_string ~body:(Yojson.Safe.to_string json) `OK
- | Error _ -> Response.create (`Code 422))
- | None -> Response.create `Not_found
- ;;
-
- let balance client_id (db_pool : Query.pool) (request : Request.t) =
- let json : Yojson.Safe.t =
- let balance =
- let total = `Int (-9098) in
- let date = `String "2024-01-17T02:34:41.217753Z" in
- let limit = `Int 100000 in
- `Assoc [ "total", total; "data_extrato", date; "limite", limit ]
- in
- let last_transactions = `List [] in
- `Assoc [ "saldo", balance; "ultimas_transacoes", last_transactions ]
- in
- Response.of_string ~body:(Yojson.Safe.to_string json) `OK
- ;;
-end
-
let routes =
List.fold_left
~f:(fun acc (v, r) -> R.add_to_list v r acc)
~init:R.empty
- [ `GET, (s "clientes" / int / s "extrato" /? nil) @--> Handler.balance
- ; `POST, (s "clientes" / int / s "transacoes" /? nil) @--> Handler.transaction
+ [ `GET, (s "clientes" / int / s "extrato" /? nil) @--> Handler.get_balance
+ ; `POST, (s "clientes" / int / s "transacoes" /? nil) @--> Handler.create_transaction
]
;;
diff --git a/script.sql b/script.sql
index 25e5ffe..7f3f3c0 100644
--- a/script.sql
+++ b/script.sql
@@ -11,8 +11,8 @@ CREATE TABLE transactions (
client_id INTEGER REFERENCES clients,
value INTEGER NOT NULL,
type transaction_type NOT NULL,
- description VARCHAR(10) NOT NULL,
- created_at TIMESTAMP NOT NULL DEFAULT NOW()
+ description VARCHAR(255) NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE balances (