123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493openLwt.Syntax(** This modules provides tools for creating more implementations of the {!Ocsipersist} virtual module. *)moduleSigs=structmoduletypeTABLE=sigtypekeytypevaluevalname:stringvalfind:key->valueLwt.tvaladd:key->value->unitLwt.tvalreplace_if_exists:key->value->unitLwt.tvalremove:key->unitLwt.tvalmodify_opt:key->(valueoption->valueoption)->unitLwt.tvallength:unit->intLwt.tvaliter:?count:int64->?gt:key->?geq:key->?lt:key->?leq:key->(key->value->unitLwt.t)->unitLwt.tvalfold:?count:int64->?gt:key->?geq:key->?lt:key->?leq:key->(key->value->'a->'aLwt.t)->'a->'aLwt.tvaliter_block:?count:int64->?gt:key->?geq:key->?lt:key->?leq:key->(key->value->unit)->unitLwt.tvaliter_batch:?count:int64->?gt:key->?geq:key->?lt:key->?leq:key->((key*value)list->unitLwt.t)->unitLwt.tmoduleVariable:sigtypetvalmake:name:key->default:value->tvalmake_lazy:name:key->default:(unit->value)->tvalmake_lazy_lwt:name:key->default:(unit->valueLwt.t)->tvalget:t->valueLwt.tvalset:t->value->unitLwt.tendendmoduletypeFUNCTORIAL=sigtypeinternalmoduletypeCOLUMN=sigtypetvalcolumn_type:stringvalencode:t->internalvaldecode:internal->tendmoduleTable(_:sigvalname:stringend)(Key:COLUMN)(Value:COLUMN):TABLEwithtypekey=Key.tandtypevalue=Value.tmoduleColumn:sigmoduleString:COLUMNwithtypet=stringmoduleFloat:COLUMNwithtypet=floatmoduleMarshal(C:sigtypetend):COLUMNwithtypet=C.tmoduleJson(C:sigtypetvalt:tDeriving_Json.tend):COLUMNwithtypet=C.tendendmoduletypePOLYMORPHIC=sigtype'valuetable(** Type of persistent table *)valtable_name:'valuetable->stringLwt.t(** returns the name of the table *)valopen_table:string->'valuetableLwt.t(** Open a table (and create it if it does not exist) *)valfind:'valuetable->string->'valueLwt.t(** [find table key] gives the value associated to [key].
Fails with [Not_found] if not found. *)valadd:'valuetable->string->'value->unitLwt.t(** [add table key value] associates [value] to [key].
If the database already contains data associated with [key],
that data is discarded and silently replaced by the new data.
*)valreplace_if_exists:'valuetable->string->'value->unitLwt.t(** [replace_if_exists table key value]
associates [value] to [key] only if [key] is already bound.
If the database does not contain any data associated with [key],
fails with [Not_found].
*)valremove:'valuetable->string->unitLwt.t(** [remove table key] removes the entry in the table if it exists *)vallength:'valuetable->intLwt.t(** Size of a table. *)valiter:(string->'a->unitLwt.t)->'atable->unitLwt.t(** Important warning: this iterator may not iter on all data of the table
if another thread is modifying it in the same time. Nonetheless, it should
not miss more than a very few data from time to time, except if the table
is very old (at least 9 223 372 036 854 775 807 insertions).
*)valfold:(string->'a->'b->'bLwt.t)->'atable->'b->'bLwt.t(** Important warning: this iterator may not iter on all data of the table
if another thread is modifying it in the same time. Nonetheless, it should
not miss more than a very few data from time to time, except if the table
is very old (at least 9 223 372 036 854 775 807 insertions).
*)valiter_step:(string->'a->unitLwt.t)->'atable->unitLwt.t[@@alertdeprecated"Use iter instead."]valfold_step:(string->'a->'b->'bLwt.t)->'atable->'b->'bLwt.t[@@alertdeprecated"Use fold instead."]valiter_block:(string->'a->unit)->'atable->unitLwt.t(** MAJOR WARNING: Unlike iter_step, this iterator won't miss any
entry and will run in one shot. It is therefore more efficient, BUT:
it will lock the WHOLE database during its execution,
thus preventing ANYBODY from accessing it (including the function f
which is iterated).
As a consequence: you MUST NOT use any function from ocsipersist in f,
otherwise you would lock yourself and everybody else! Be VERY cautious.
*)endmoduletypeREF=sig(** Persistent references for OCaml *)type'at(** The type of (persistent or not) references *)valref:?persistent:string->'a->'at(** [ref ?persistent default] creates a reference.
If optional parameter [?persistent] is absent,
the reference will not be persistent (implemented using OCaml references).
Otherwise, the value of [persistent] will be used as key for the
value in the persistent reference table.
If the reference already exists, the current value is kept.
Be careful to change this name every time you change the type of the
value. *)valget:'at->'aLwt.t(** Get the value of a reference *)valset:'at->'a->unitLwt.t(** Set the value of a reference *)endmoduletypeSTORE=sigtype'at(** Type of persistent data *)typestore(** Data are divided into stores.
Create one store for your project, where you will save all your data. *)valopen_store:string->storeLwt.t(** Open a store (and create it if it does not exist) *)valmake_persistent:store:store->name:string->default:'a->'atLwt.t(** [make_persistent store name default] find a persistent value
named [name] in store [store]
from database, or create it with the default value [default] if it
does not exist. *)valmake_persistent_lazy:store:store->name:string->default:(unit->'a)->'atLwt.t(** Same as make_persistent but the default value is evaluated only
if needed
*)valmake_persistent_lazy_lwt:store:store->name:string->default:(unit->'aLwt.t)->'atLwt.t(** Lwt version of make_persistent_lazy.
*)valget:'at->'aLwt.t(** [get pv] gives the value of [pv] *)valset:'at->'a->unitLwt.t(** [set pv value] sets a persistent value [pv] to [value] *)endmoduletypeREF_JSON=sig(** Type-safe persistent references using {!Deriving_Json} for
serialisation. *)type'at(** The type of (persistent or not) references *)valref:?persistent:string->'aDeriving_Json.t->'a->'at(** [ref ?persistent json default] creates a reference.
If optional parameter [?persistent] is absent,
the reference will not be persistent (implemented using OCaml references).
Otherwise, the value of [persistent] will be used as key for the
value in the persistent reference table.
If the reference already exists, the current value is kept. *)valget:'at->'aLwt.t(** Get the value of a reference *)valset:'at->'a->unitLwt.t(** Set the value of a reference *)endmoduletypeSTORE_JSON=sigtype'at(** Type of persistent data *)typestore(** Data are divided into stores.
Create one store for your project, where you will save all your data. *)valopen_store:string->storeLwt.t(** Open a store (and create it if it does not exist) *)valmake_persistent:store:store->name:string->json:'aDeriving_Json.t->default:'a->'atLwt.t(** [make_persistent ~store ~name ~json ~default] find a persistent value
named [name] in store [store]
from database, or create it with the default value [default] if it
does not exist. Uses {!Deriving_Json} for type-safe serialisation. *)valmake_persistent_lazy:store:store->name:string->json:'aDeriving_Json.t->default:(unit->'a)->'atLwt.t(** Same as make_persistent but the default value is evaluated only
if needed *)valmake_persistent_lazy_lwt:store:store->name:string->json:'aDeriving_Json.t->default:(unit->'aLwt.t)->'atLwt.t(** Lwt version of make_persistent_lazy. *)valget:'at->'aLwt.t(** [get pv] gives the value of [pv] *)valset:'at->'a->unitLwt.t(** [set pv value] sets a persistent value [pv] to [value] *)endendopenSigsopenLwt.Infixletis_valid_name_char=function|'a'..'z'|'A'..'Z'|'0'..'9'|'_'->true|_->falseletvalidate_namename=ifString.lengthname=0theninvalid_arg"Ocsipersist: table/store name must not be empty"elseifnot(String.for_allis_valid_name_charname)theninvalid_arg(Printf.sprintf"Ocsipersist: invalid table/store name %S (only [a-zA-Z0-9_] allowed)"name)(** deriving polymorphic interface from the functorial one *)modulePolymorphic(Functorial:FUNCTORIAL):POLYMORPHIC=structmoduletypePOLYMORPHIC=TABLEwithtypekey=stringtype'valuetable=(modulePOLYMORPHICwithtypevalue='value)letopen_table(typea)name=validate_namename;letopenFunctorialinletmoduleT=Table(structletname=nameend)(Column.String)(Column.Marshal(structtypet=aend))inLwt.return(moduleT:POLYMORPHICwithtypevalue=a)lettable_name(typea)(moduleT:POLYMORPHICwithtypevalue=a)=Lwt.returnT.nameletfind(typea)(moduleT:POLYMORPHICwithtypevalue=a)=T.findletadd(typea)(moduleT:POLYMORPHICwithtypevalue=a)=T.addletreplace_if_exists(typea)(moduleT:POLYMORPHICwithtypevalue=a)=T.replace_if_existsletremove(typea)(moduleT:POLYMORPHICwithtypevalue=a)=T.removeletlength(typea)(moduleT:POLYMORPHICwithtypevalue=a)=T.length()letiter(typea)f(moduleT:POLYMORPHICwithtypevalue=a)=T.iterfletfold(typea)f(moduleT:POLYMORPHICwithtypevalue=a)=T.foldfletiter_step=iterletfold_step=foldletiter_block(typea)f(moduleT:POLYMORPHICwithtypevalue=a)=T.iter_blockfendmoduleVariable(T:sigtypektypevvalfind:k->vLwt.tvaladd:k->v->unitLwt.tend)=structtypet={name:T.k;default:unit->T.vLwt.t}letmake_lazy_lwt~name~default={name;default}letmake_lazy~name~default={name;default=(fun()->Lwt.return@@default())}letmake~name~default={name;default=(fun()->Lwt.returndefault)}letget{name;default}=Lwt.catch(fun()->T.findname)(function|Not_found->default()>>=fund->T.addnamed>>=fun()->Lwt.returnd|exc->Lwt.reraiseexc)letset{name;_}=T.addnameendmoduleRef(Store:STORE)=structletstore=lazy(Store.open_store"__ocsipersist_ref_store__")type'at=Refof'aref|Perof'aStore.tLwt.tletref?persistentv=matchpersistentwith|None->Ref(refv)|Somename->Per(let*store=Lazy.forcestoreinStore.make_persistent~store~name~default:v)letget=function|Refr->Lwt.return!r|Perr->let*r=rinStore.getrletsetrv=matchrwith|Refr->r:=v;Lwt.return_unit|Perr->let*r=rinStore.setrvendmoduleStore_json(Functorial:FUNCTORIAL):STORE_JSON=structtypestore=stringtype'at={find:unit->'aLwt.t;add:'a->unitLwt.t}letopen_storename=validate_namename;Lwt.return("store_json___"^name)letmake_persistent_lazy_lwt(typea)~store~name~(json:aDeriving_Json.t)~default=letopenFunctorialinletmoduleT=Table(structletname=storeend)(Column.String)(Column.Json(structtypet=alett=jsonend))inletfind()=T.findnameinletaddv=T.addnamevinLwt.catch(fun()->find()>>=fun_->Lwt.return())(function|Not_found->default()>>=fundef->adddef|e->Lwt.faile)>>=fun()->Lwt.return{find;add}letmake_persistent_lazy~store~name~json~default=letdefault()=Lwt.wrapdefaultinmake_persistent_lazy_lwt~store~name~json~defaultletmake_persistent~store~name~json~default=make_persistent_lazy~store~name~json~default:(fun()->default)letgett=t.find()letsettv=t.addvendmoduleRef_json(Functorial:FUNCTORIAL):REF_JSON=structmoduleS=Store_json(Functorial)letstore=lazy(S.open_store"__ocsipersist_ref_json_store__")type'at=Refof'aref|Perof'aS.tLwt.tletref(typea)?persistent(json:aDeriving_Json.t)v=matchpersistentwith|None->Ref(refv)|Somename->Per(let*store=Lazy.forcestoreinS.make_persistent~store~name~json~default:v)letget=function|Refr->Lwt.return!r|Perr->let*r=rinS.getrletsetrv=matchrwith|Refr->r:=v;Lwt.return_unit|Perr->let*r=rinS.setrvend