123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223openBaseopenPpxlibmoduleBuildef=Ast_builder.Defaulttypeextension_contents={in_params:Query.paramlist;out_params:Query.paramlist;record_in:bool;record_out:bool;}exceptionErrorofstring(** [up_to_last (xs @ [x])] returns [xs] *)letup_to_lastxs=List.takexs(List.lengthxs-1)(** Produces individual Caqti types from parsed parameters *)letcaqti_type_of_param~locQuery.{typ;opt;_}=letbase_expr=matchtypwith|None,base_type->(matchbase_typewith|"string"->[%exprstring]|"octets"->[%exproctets]|"int"->[%exprint]|"int32"->[%exprint32]|"int64"->[%exprint64]|"bool"->[%exprbool]|"float"->[%exprfloat]|"pdate"->[%exprpdate]|"ptime"->[%exprptime]|"ptime_span"->[%exprptime_span]|other->raise(Error(Printf.sprintf"Base type '%s' not supported"other)))|Somemodule_name,typ->Buildef.pexp_ident~loc(Loc.make~loc(Ldot(Lidentmodule_name,typ)))inmatchoptwith|true->Buildef.(pexp_apply~loc[%exproption][(Nolabel,base_expr)])|false->base_expr(** Makes Caqti type specifications like [string & option int & bool] *)letmake_caqti_type_tup~locparams=matchList.lengthparamswith|0->[%exprunit]|_->lettype_exprs=List.map~f:(caqti_type_of_param~loc)paramsinletfelem_type_exprapply_expr=[%exprtup2[%eelem_type_expr][%eapply_expr]]inList.fold_right~f~init:(List.last_exntype_exprs)(up_to_lasttype_exprs)letlident_of_param~locparam=Loc.make~loc(Lidentparam.Query.name)letvar_of_param~locparam=Loc.make~locparam.Query.name(** Maps parsed parameters to ident expressions of their names *)letpexp_idents_of_params~locparams=List.map~f:(funparam->Buildef.pexp_ident~loc(lident_of_param~locparam))paramsletppat_of_param~locparam=Buildef.ppat_var~loc(var_of_param~locparam)(** Maps parsed parameters to var patterns of their names *)letppat_var_of_params~locparams=List.map~f:(ppat_of_param~loc)params(** General function for producing ASTs for [(a, (b, (c, (d, e))))] as either expressions or patterns *)letnested_tuple_thingzero_casemappertuple_maker~locparams=matchList.lengthparamswith(* With current design, 0-tuple case should not occur. *)|0->zero_case|_->letidents=mapper~locparamsinletfidentaccum=tuple_maker~loc[ident;accum]inList.fold_right~f~init:(List.last_exnidents)(up_to_lastidents)(** Makes [(a, (b, (c, (d, e))))] expression ASTs from parsed parameters *)letnested_tuple_expression~loc=nested_tuple_thing[%expr()]pexp_idents_of_paramsBuildef.pexp_tuple~loc(** Makes [(a, (b, (c, (d, e))))] pattern ASTs from parsed parameters *)letnested_tuple_pattern~loc=nested_tuple_thing(Buildef.ppat_tuple~loc[])ppat_var_of_paramsBuildef.ppat_tuple~loc(** Makes [(a, b, c, d, e)] expression ASTs from parsed parameters *)letflat_tuple~locparams=Buildef.pexp_tuple~loc(pexp_idents_of_params~locparams)(** Makes [{a; b; c; d; e}] expression ASTs from parsed parameters *)letrecord_expression~locparams=letfparam=letlident=lident_of_param~locparamin(lident,Buildef.pexp_ident~loclident)inletpair_list=List.mapparams~finBuildef.pexp_record~locpair_listNone(** Makes [{a; b; c; d; e}] pattern ASTs from parsed parameters *)letrecord_pattern~locparams=letfparam=letlident=lident_of_param~locparaminletvar=var_of_param~locparamin(lident,Buildef.ppat_var~locvar)inletpair_list=List.mapparams~finBuildef.ppat_record~locpair_listClosed(** Generates the function body for an [exec] function ([execute] statement) *)letfunction_body_exec~locconnection_function_expr{in_params;record_out;_}=assert(notrecord_out);letinput_nested_tuples=nested_tuple_expression~locin_paramsin[%expr[%econnection_function_expr]query[%einput_nested_tuples]]letfunction_body_general~locfactoryconnection_function_expr{in_params;out_params;record_out;_}=letinput_nested_tuple_expression=nested_tuple_expression~locin_paramsinmatch(List.lengthout_params,record_out)with|0,true->raise(Error"'record_out' should not be set when there are no output parameters")|0,false|1,false->[%expr[%econnection_function_expr]query[%einput_nested_tuple_expression]]|1,true|_->letinput_nested_tuple_pattern=nested_tuple_pattern~locout_paramsinletoutput_expression=ifrecord_outthenrecord_expression~locout_paramselseflat_tuple~locout_paramsinfactory~locinput_nested_tuple_patternoutput_expressionconnection_function_exprinput_nested_tuple_expressionletfind_body_factory~locinput_nested_tuple_patternoutput_expressionconnection_function_exprinput_nested_tuple_expression=[%exprletfresult=matchresultwith|Ok[%pinput_nested_tuple_pattern]->Ok[%eoutput_expression]|Errore->ErroreinLwt.mapf([%econnection_function_expr]query[%einput_nested_tuple_expression])]letfind_map_factory~locmap_exprinput_nested_tuple_patternoutput_expressionconnection_function_exprinput_nested_tuple_expression=[%exprletfresult=letg[%pinput_nested_tuple_pattern]=[%eoutput_expression]inletf=[%emap_expr]ginmatchresultwithOkx->Ok(fx)|Errore->ErroreinLwt.mapf([%econnection_function_expr]query[%einput_nested_tuple_expression])](** Generates the function body for a [find] function ([get_one] statement)*)letfunction_body_find~loc=function_body_general~locfind_body_factory(** Generates the function body for cases where it has involves a map
* These are [find_opt] and [collect_list] (for [get_opt] and [get_many] statements). *)letfunction_body_map~locmap_expr=function_body_general~loc(find_map_factorymap_expr)(** Generates the function body for a [find_opt] function ([get_opt] statement) *)letfunction_body_find_opt~loc=function_body_map~loc[%exprfunfx->matchxwithSomex->Some(fx)|None->None](** Generates the function body for a [collect_list] function ([get_many] statement) *)letfunction_body_collect~loc=function_body_map~loc[%exprList.map](** Generates code like [fun ~x ~y ~z -> Db.some_function query (x, (y, z))]. *)letquery_function~loc?(body_fn=funx->x)function_body_factoryconnection_function_exprexpression_contents=(* Tuples should have duplicates if they exist. *)letbody=function_body_factory~locconnection_function_exprexpression_contents|>body_fninletin_params=expression_contents.in_paramsinletdeduped_in_params=matchQuery.remove_duplicatesin_paramswith|Okdeduplicated->deduplicated|Error_->raise(Error"Duplicated input parameters with conflicting specs")inmatchexpression_contents.record_inwith|true->ifList.is_emptyin_paramsthenraise(Error"'record_in' should not be set when there are no input parameters")elseletinput_record_pattern=record_pattern~locdeduped_in_paramsin[%exprfun[%pinput_record_pattern]->[%ebody]]|false->ifList.is_emptyin_paramsthen[%exprfun()->[%ebody]]elseletfin_parambody_so_far=letname=in_param.Query.nameinletpattern=Buildef.ppat_var~loc(Loc.make~locname)inBuildef.pexp_fun~loc(Labelledname)Nonepatternbody_so_farinList.fold_right~f~init:bodydeduped_in_paramsletexec_function~body_fn~loc=query_function~loc~body_fnfunction_body_exec[%exprDb.exec]letfind_function~body_fn~loc=query_function~loc~body_fnfunction_body_find[%exprDb.find]letfind_opt_function~body_fn~loc=query_function~loc~body_fnfunction_body_find_opt[%exprDb.find_opt]letcollect_list_function~body_fn~loc=query_function~loc~body_fnfunction_body_collect[%exprDb.collect_list]