Skip to content

Instantly share code, notes, and snippets.

@painedpineapple
Created February 21, 2020 17:01
Show Gist options
  • Save painedpineapple/3c91830e75b708a6c78ce414e8ddef8f to your computer and use it in GitHub Desktop.
Save painedpineapple/3c91830e75b708a6c78ce414e8ddef8f to your computer and use it in GitHub Desktop.
/** Dependencies
* @glennsl/bs-json: Encoding Data
* bs-decode: Decoding Data
**/
open Belt.Result;
[@bs.val] [@bs.scope "localStorage"]
external removeItem: string => unit = "removeItem";
[@bs.val] [@bs.scope "localStorage"]
external getItem: string => Js.Nullable.t(string) = "getItem";
[@bs.val] [@bs.scope "localStorage"]
external setItem: (string, string) => unit = "setItem";
type itemWithExpiration('a) = {
expiresAt: float,
data: 'a,
};
module Decoder = {
module D = Decode.AsResult.OfParseError;
let itemWithExpiration = (json, dataDecoder) =>
D.Pipeline.(
succeed((expiresAt, data) => {expiresAt, data})
->field("expiresAt", D.floatFromNumber, _)
->field("data", dataDecoder, _)
->run(json, _)
);
};
module Encode = {
open Json;
let itemWithExpiration = (item, dataEncoder) =>
Json.Encode.(
object_([
("expiresAt", Encode.float(item.expiresAt)),
("data", dataEncoder(item.data)),
])
);
};
exception ItemWithExpirationJson(string);
let getItemWithExpiration = (storage_key, decoder) =>
switch (getItem(storage_key)->Js.Nullable.toOption) {
| None =>
None;
| Some(json) =>
switch (json->Js.Json.parseExn->Decoder.itemWithExpiration(decoder)) {
| Ok(cache) =>
if (DateFns.isBefore(
Js.Date.fromFloat(cache.expiresAt),
Js.Date.make(),
)) {
Some(cache.data);
} else {
None;
}
| Error(error) =>
Js.log(Decode.ParseError.failureToDebugString(error));
None;
};
};
let setItemWithExpiration = (storage_key, data, encoder) =>
{expiresAt: DateFns.addDays(1., Js.Date.make())->Js.Date.getTime, data}
->Encode.itemWithExpiration(encoder)
->Js.Json.stringify
|> setItem(storage_key);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment