open Syntax open Caqti_request.Infix open Caqti_type (* todo better: make emojid just string and not string list in this module; problem is we have to split on unicode *) module Q = struct (* we save emojid in a string with emoji separated by '-' *) let upload_emojid uuid emojid = let emojid = String.concat "-" emojid in Db.exec ((tup2 string string ->. unit) "INSERT INTO uuid_emojid VALUES (?,?)") (uuid, emojid) let get_emojid uuid = Db.find ((string ->! string) "SELECT emojid FROM uuid_emojid WHERE uuid=?") uuid |> Result.map (String.split_on_char '-') let get_all_emojid () = let* l = Db.collect_list ((unit ->* string) "SELECT emojid FROM uuid_emojid") () in Ok (List.map (String.split_on_char '-') l) end module Trie = CCTrie.Make (struct type t = string list type char_ = string let compare = String.compare let to_iter o f = List.iter f o let of_list = Fun.id end) let max_emojid_lenght = 16 let alphabet = Array.append Emoji.category_animals_and_nature Emoji.category_food_and_drink let trie = let tables = [| (unit ->. unit) "CREATE TABLE IF NOT EXISTS uuid_emojid (uuid TEXT, emojid TEXT)" |] in if Array.exists Result.is_error (Array.map (fun query -> Db.exec query ()) tables) then failwith "can't create emojid's tables" else match Q.get_all_emojid () with | Error e -> failwith (Format.sprintf "Error with Emojid.Q.select_all: %s" e) | Ok l -> let l = List.map (fun e -> (e, ())) l in ref (Trie.of_list l) let make uuid = (* pick a list of emojis *) let random_emojis = List.init max_emojid_lenght (fun _i -> let n = Random.int (Array.length alphabet) in Array.get alphabet n ) in (* pick the smallest emojid possible *) let longest_prefix = Trie.longest_prefix random_emojis !trie in (* add one more emoji to longest_prefix *) match List.nth_opt random_emojis (List.length longest_prefix) with | None -> Dream.error (fun log -> log "Emojid error: longest prefix is too long"); Error "Could not create emojid" | Some x -> let emojid = longest_prefix @ [ x ] in let* () = Q.upload_emojid uuid emojid in trie := Trie.add emojid () !trie; Ok (String.concat "" emojid) let get uuid = let* l = Q.get_emojid uuid in Ok (String.concat "" l)