From c7f074fb394005363ee72cb8a00ca26e3f9e4034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Fri, 15 Mar 2019 11:32:06 +0100 Subject: [PATCH] =?UTF-8?q?[server]=C2=A0better=20processing=20of=20named?= =?UTF-8?q?=20parameters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/server/request.ml | 96 ++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/src/plugins/server/request.ml b/src/plugins/server/request.ml index ca448e9a289..a584b3f4ac7 100644 --- a/src/plugins/server/request.ml +++ b/src/plugins/server/request.ml @@ -187,20 +187,6 @@ type _ rq_output = | Rdata : 'a output -> 'a rq_output | Rfields : Syntax.field list -> unit rq_output -(* json input processing *) -let mk_input (type a) name (input : a rq_input) : (rq -> json -> a) = - match input with - | Pnone -> Senv.fatal "No input defined for request '%s'" name - | Pdata d -> let module D = (val d) in (fun _rq js -> D.of_json js) - | Pfields _ -> (fun rq js -> rq.param <- fmap_of_json rq.param js) - -(* json output processing *) -let mk_output (type b) name (output : b rq_output) : (rq -> b -> json) = - match output with - | Rnone -> Senv.fatal "No output defined for request '%s'" name - | Rdata d -> let module D = (val d) in (fun _rq v -> D.to_json v) - | Rfields _ -> (fun rq () -> fmap_to_json rq.result) - (* json input syntax *) let sy_input (type a) (input : a rq_input) : Syntax.t = match input with @@ -229,20 +215,6 @@ let doc_output (type b) (output : b rq_output) : Markdown.block = | Rdata _ -> Markdown.empty | Rfields fs -> Syntax.fields ~kind:"Output" (List.rev fs) -(* current input fields *) -let fds_input (type a) name (input : a rq_input) : Syntax.field list = - match input with - | Pdata _ -> Senv.fatal "Can not define named parameters for request '%s'" name - | Pnone -> [] - | Pfields fds -> fds - -(* current output fields *) -let fds_output (type a) name (output : a rq_output) : Syntax.field list = - match output with - | Rdata _ -> Senv.fatal "Can not define named results request '%s'" name - | Rnone -> [] - | Rfields fds -> fds - (* -------------------------------------------------------------------------- *) (* --- Multi-Parameters Requests --- *) (* -------------------------------------------------------------------------- *) @@ -255,6 +227,7 @@ type ('a,'b) signature = { details : Markdown.block ; mutable defined : bool ; mutable defaults : json Fmap.t ; + mutable required : string list ; mutable input : 'a rq_input ; mutable output : 'b rq_output ; } @@ -264,10 +237,22 @@ let failure_missing name fmap = (Printf.sprintf "Missing parameter '%s'" name) (fmap_to_json fmap) +let check_required fmap fd = + if not (Fmap.mem fd fmap) then failure_missing fd fmap + (* -------------------------------------------------------------------------- *) (* --- Named Input Parameters Definitions --- *) (* -------------------------------------------------------------------------- *) +(* current input fields *) +let fds_input s : Syntax.field list = + if s.defined then Senv.failure "Request '%s' has been finalized." s.name ; + match s.input with + | Pdata _ -> + Senv.fatal "Can not define named parameters for request '%s'" s.name + | Pnone -> [] + | Pfields fds -> fds + let param (type a b) (s : (unit,b) signature) ~name ~descr ?default (input : a input) : a param = let module D = (val input) in @@ -277,7 +262,7 @@ let param (type a b) (s : (unit,b) signature) ~name ~descr fd_default = None ; fd_descr = descr ; } in - s.input <- Pfields (fd :: fds_input s.name s.input) ; + s.input <- Pfields (fd :: fds_input s) ; fun rq -> try D.of_json (Fmap.find name rq.param) with Not_found -> @@ -285,7 +270,7 @@ let param (type a b) (s : (unit,b) signature) ~name ~descr | None -> failure_missing name rq.param | Some v -> v -let param_opt (type a b) (rq : (unit,b) signature) ~name ~descr +let param_opt (type a b) (s : (unit,b) signature) ~name ~descr (input : a input) : a option param = let module D = (val input) in let fd = Syntax.{ @@ -294,7 +279,7 @@ let param_opt (type a b) (rq : (unit,b) signature) ~name ~descr fd_default = None ; fd_descr = descr ; } in - rq.input <- Pfields (fd :: fds_input rq.name rq.input) ; + s.input <- Pfields (fd :: fds_input s) ; fun rq -> try Some(D.of_json (Fmap.find name rq.param)) with Not_found -> None @@ -303,6 +288,14 @@ let param_opt (type a b) (rq : (unit,b) signature) ~name ~descr (* --- Named Output Parameters Definitions --- *) (* -------------------------------------------------------------------------- *) +(* current output fields *) +let fds_output s : Syntax.field list = + if s.defined then Senv.failure "Request '%s' has been finalized." s.name ; + match s.output with + | Rdata _ -> Senv.fatal "Can not define named results request '%s'" s.name + | Rnone -> [] + | Rfields fds -> fds + let result (type a b) (s : (a,unit) signature) ~name ~descr ?default (output : b output) : b result = let module D = (val output) in @@ -312,9 +305,12 @@ let result (type a b) (s : (a,unit) signature) ~name ~descr fd_default = None ; fd_descr = descr ; } in - s.output <- Rfields (fd :: fds_output s.name s.output) ; - ( match default with None -> () | Some v -> - s.defaults <- Fmap.add name (D.to_json v) s.defaults ) ; + s.output <- Rfields (fd :: fds_output s) ; + begin + match default with + | None -> s.required <- name :: s.required + | Some v -> s.defaults <- Fmap.add name (D.to_json v) s.defaults + end ; fun rq v -> rq.result <- Fmap.add name (D.to_json v) rq.result let result_opt (type a b) (s : (a,unit) signature) ~name ~descr @@ -326,7 +322,7 @@ let result_opt (type a b) (s : (a,unit) signature) ~name ~descr fd_default = None ; fd_descr = descr ; } in - s.output <- Rfields (fd :: fds_output s.name s.output) ; + s.output <- Rfields (fd :: fds_output s) ; fun rq opt -> match opt with None -> () | Some v -> rq.result <- Fmap.add name (D.to_json v) rq.result @@ -345,7 +341,7 @@ let signature let output = match output with None -> Rnone | Some d -> Rdata d in { page ; kind ; name ; descr ; details ; - defaults = Fmap.empty ; + defaults = Fmap.empty ; required = [] ; input ; output ; defined = false ; } @@ -353,14 +349,34 @@ let signature (* --- Opened Signature Process --- *) (* -------------------------------------------------------------------------- *) +(* json input processing *) +let mk_input (type a) name defaults (input : a rq_input) : (rq -> json -> a) = + match input with + | Pnone -> Senv.fatal "No input defined for request '%s'" name + | Pdata d -> + let module D = (val d) in + (fun rq js -> rq.result <- defaults ; D.of_json js) + | Pfields _ -> + (fun rq js -> rq.param <- fmap_of_json rq.param js) + +(* json output processing *) +let mk_output (type b) name required (output : b rq_output) : (rq -> b -> json) = + match output with + | Rnone -> Senv.fatal "No output defined for request '%s'" name + | Rdata d -> + let module D = (val d) in (fun _rq v -> D.to_json v) + | Rfields _ -> + (fun rq () -> + List.iter (check_required rq.result) required ; + fmap_to_json rq.result) + let register_sig (type a b) (s : (a,b) signature) (process : rq -> a -> b) = if s.defined then Senv.fatal "Request '%s' is defined twice" s.name ; - let input = mk_input s.name s.input in - let output = mk_output s.name s.output in - let defaults = s.defaults in + let input = mk_input s.name s.defaults s.input in + let output = mk_output s.name s.required s.output in let processor js = - let rq = { param = Fmap.empty ; result = defaults } in + let rq = { param = Fmap.empty ; result = Fmap.empty } in js |> input rq |> process rq |> output rq in let skind = Main.string_of_kind s.kind in -- GitLab